From 5ede6776304ee1aef93f2fd81d92f46d34f546af Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Tue, 21 May 2024 18:09:55 -0400 Subject: [PATCH 01/69] Commit solution --- calculate_average_havelessbemore.sh | 18 + .../nodejs/havelessbemore/.prettierignore | 3 + src/main/nodejs/havelessbemore/AUTHORS | 1 + src/main/nodejs/havelessbemore/CHANGELOG.md | 12 + src/main/nodejs/havelessbemore/dist/index.cjs | 387 +++ .../nodejs/havelessbemore/dist/index.cjs.map | 1 + src/main/nodejs/havelessbemore/dist/index.mjs | 384 +++ .../nodejs/havelessbemore/dist/index.mjs.map | 1 + .../nodejs/havelessbemore/eslint.config.js | 22 + .../nodejs/havelessbemore/package-lock.json | 2871 +++++++++++++++++ src/main/nodejs/havelessbemore/package.json | 36 + .../nodejs/havelessbemore/rollup.config.ts | 32 + .../src/constants/constraints.ts | 25 + .../havelessbemore/src/constants/stream.ts | 39 + .../havelessbemore/src/constants/trie.ts | 76 + .../havelessbemore/src/constants/utf8.ts | 43 + .../havelessbemore/src/constants/workers.ts | 9 + src/main/nodejs/havelessbemore/src/index.ts | 24 + src/main/nodejs/havelessbemore/src/main.ts | 123 + .../havelessbemore/src/types/workerRequest.ts | 6 + .../src/types/workerResponse.ts | 8 + .../nodejs/havelessbemore/src/utils/stream.ts | 102 + .../nodejs/havelessbemore/src/utils/trie.ts | 218 ++ src/main/nodejs/havelessbemore/src/worker.ts | 107 + src/main/nodejs/havelessbemore/tsconfig.json | 115 + 25 files changed, 4663 insertions(+) create mode 100755 calculate_average_havelessbemore.sh create mode 100644 src/main/nodejs/havelessbemore/.prettierignore create mode 100644 src/main/nodejs/havelessbemore/AUTHORS create mode 100644 src/main/nodejs/havelessbemore/CHANGELOG.md create mode 100644 src/main/nodejs/havelessbemore/dist/index.cjs create mode 100644 src/main/nodejs/havelessbemore/dist/index.cjs.map create mode 100644 src/main/nodejs/havelessbemore/dist/index.mjs create mode 100644 src/main/nodejs/havelessbemore/dist/index.mjs.map create mode 100644 src/main/nodejs/havelessbemore/eslint.config.js create mode 100644 src/main/nodejs/havelessbemore/package-lock.json create mode 100644 src/main/nodejs/havelessbemore/package.json create mode 100644 src/main/nodejs/havelessbemore/rollup.config.ts create mode 100644 src/main/nodejs/havelessbemore/src/constants/constraints.ts create mode 100644 src/main/nodejs/havelessbemore/src/constants/stream.ts create mode 100644 src/main/nodejs/havelessbemore/src/constants/trie.ts create mode 100644 src/main/nodejs/havelessbemore/src/constants/utf8.ts create mode 100644 src/main/nodejs/havelessbemore/src/constants/workers.ts create mode 100644 src/main/nodejs/havelessbemore/src/index.ts create mode 100644 src/main/nodejs/havelessbemore/src/main.ts create mode 100644 src/main/nodejs/havelessbemore/src/types/workerRequest.ts create mode 100644 src/main/nodejs/havelessbemore/src/types/workerResponse.ts create mode 100644 src/main/nodejs/havelessbemore/src/utils/stream.ts create mode 100644 src/main/nodejs/havelessbemore/src/utils/trie.ts create mode 100644 src/main/nodejs/havelessbemore/src/worker.ts create mode 100644 src/main/nodejs/havelessbemore/tsconfig.json diff --git a/calculate_average_havelessbemore.sh b/calculate_average_havelessbemore.sh new file mode 100755 index 0000000..2795552 --- /dev/null +++ b/calculate_average_havelessbemore.sh @@ -0,0 +1,18 @@ +#!/bin/sh +# +# Copyright 2023 The original authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +time node --enable-source-maps src/main/nodejs/havelessbemore/dist/index.mjs measurements.txt diff --git a/src/main/nodejs/havelessbemore/.prettierignore b/src/main/nodejs/havelessbemore/.prettierignore new file mode 100644 index 0000000..381e69d --- /dev/null +++ b/src/main/nodejs/havelessbemore/.prettierignore @@ -0,0 +1,3 @@ +.husky +dist +docs \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/AUTHORS b/src/main/nodejs/havelessbemore/AUTHORS new file mode 100644 index 0000000..ce7e462 --- /dev/null +++ b/src/main/nodejs/havelessbemore/AUTHORS @@ -0,0 +1 @@ +Michael Rojas \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/CHANGELOG.md b/src/main/nodejs/havelessbemore/CHANGELOG.md new file mode 100644 index 0000000..5a8f14b --- /dev/null +++ b/src/main/nodejs/havelessbemore/CHANGELOG.md @@ -0,0 +1,12 @@ +# Change Log + +## v0.0.1 (2024-05-15) + +- Make a copy of baseline +- Translate baseline into TypeScript + +### Performance + +| real | user | sys | +| --------- | --------- | -------- | +| 5m44.952s | 5m41.587s | 0m4.377s | diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs b/src/main/nodejs/havelessbemore/dist/index.cjs new file mode 100644 index 0000000..8e91dc3 --- /dev/null +++ b/src/main/nodejs/havelessbemore/dist/index.cjs @@ -0,0 +1,387 @@ +'use strict'; + +var os = require('node:os'); +var node_url = require('node:url'); +var node_worker_threads = require('node:worker_threads'); +var node_fs = require('node:fs'); +var promises = require('fs/promises'); + +var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null; +const MAX_STATIONS = 1e4; +const STATION_NAME_MAX_LEN = 100; +const ENTRY_MAX_LEN = 107; + +const CHAR_MINUS = 45; +const CHAR_NEWLINE = 10; +const CHAR_SEMICOLON = 59; +const CHAR_ZERO = 48; +const UTF8_2B_MAX = 224; +const UTF8_PRINT_OFFSET = 32; +const UTF8_2B_PRINT_MAX = UTF8_2B_MAX - UTF8_PRINT_OFFSET; + +const HIGH_WATER_MARK_MIN = 16384; +const HIGH_WATER_MARK_MAX = 1048576; +const HIGH_WATER_MARK_OUT = 1048576; +const HIGH_WATER_MARK_RATIO = 152e-6; +const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN; +const CHAR_ZERO_11 = 11 * CHAR_ZERO; +const CHAR_ZERO_111 = 111 * CHAR_ZERO; + +const MIN_WORKERS = 1; +const MAX_WORKERS = 512; + +function clamp(value, min, max) { + return value > min ? value <= max ? value : max : min; +} +async function getFileChunks(filePath, target, maxLineLength, minSize = 0) { + const file = await promises.open(filePath); + try { + const size = (await file.stat()).size; + const chunkSize = Math.max(minSize, Math.floor(size / target)); + const buffer = Buffer.allocUnsafe(maxLineLength); + const chunks = []; + let start = 0; + for (let end = chunkSize; end < size; end += chunkSize) { + const res = await file.read(buffer, 0, maxLineLength, end); + const newline = buffer.indexOf(CHAR_NEWLINE); + if (newline >= 0 && newline < res.bytesRead) { + end += newline + 1; + chunks.push([start, end]); + start = end; + } + } + if (start < size) { + chunks.push([start, size]); + } + return chunks; + } finally { + await file.close(); + } +} +function getHighWaterMark(size) { + size *= HIGH_WATER_MARK_RATIO; + size = Math.round(Math.log2(size)); + size = 2 ** size; + return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX); +} + +const TRIE_NULL = 0; +const MIN_TRIE_SIZE = 524288; +const TRIE_GROWTH_FACTOR = 1.618; +const TRIE_MAX_CHILDREN = UTF8_2B_PRINT_MAX; +const TRIE_CHILD_IDX_IDX = 0; +const TRIE_CHILD_IDX_LEN = 1; +const TRIE_CHILD_LEN = TRIE_CHILD_IDX_LEN; +const TRIE_RED_ID_IDX = 0; +const TRIE_RED_ID_LEN = 1; +const TRIE_RED_VALUE_IDX_IDX = 1; +const TRIE_RED_VALUE_IDX_LEN = 1; +const TRIE_RED_LEN = TRIE_RED_ID_LEN + TRIE_RED_VALUE_IDX_LEN; +const TRIE_NODE_ID_IDX = 0; +const TRIE_NODE_ID_LEN = 1; +const TRIE_NODE_VALUE_ID_IDX = 1; +const TRIE_NODE_VALUE_ID_LEN = 1; +const TRIE_NODE_VALUE_IDX_IDX = 2; +const TRIE_NODE_VALUE_IDX_LEN = 1; +const TRIE_NODE_CHILDREN_IDX = 3; +const TRIE_NODE_CHILDREN_LEN = TRIE_CHILD_LEN * TRIE_MAX_CHILDREN; +const TRIE_NODE_LEN = TRIE_NODE_ID_LEN + TRIE_NODE_VALUE_ID_LEN + TRIE_NODE_VALUE_IDX_LEN + TRIE_NODE_CHILDREN_LEN; +const TRIE_SIZE_IDX = 0; +const TRIE_SIZE_LEN = 1; +const TRIE_ROOT_IDX = 1; +const TRIE_ROOT_LEN = TRIE_NODE_LEN; +const TRIE_HEADER_LEN = TRIE_SIZE_LEN + TRIE_ROOT_LEN; +const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX; + +function add(trie, key, min, max) { + let index = TRIE_ROOT_IDX; + while (min < max) { + index += TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_LEN * (key[min++] - UTF8_PRINT_OFFSET); + let child = trie[index + TRIE_CHILD_IDX_IDX]; + if (child === TRIE_NULL) { + child = trie[TRIE_SIZE_IDX]; + if (child + TRIE_NODE_LEN > trie.length) { + trie = grow(trie, child + TRIE_NODE_LEN); + } + trie[TRIE_SIZE_IDX] += TRIE_NODE_LEN; + trie[index + TRIE_CHILD_IDX_IDX] = child; + trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX]; + } + index = child; + } + return [trie, index]; +} +function createTrie(id = 0, size = MIN_TRIE_SIZE) { + const minSize = TRIE_HEADER_LEN; + const trie = new Int32Array(Math.max(minSize, size)); + trie[TRIE_SIZE_IDX] = minSize; + trie[TRIE_ID_IDX] = id; + return trie; +} +function grow(trie, minSize = 0) { + const length = trie[TRIE_SIZE_IDX]; + minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR)); + const next = new Int32Array(minSize); + for (let i = 0; i < length; ++i) { + next[i] = trie[i]; + } + return next; +} +function mergeLeft(tries, at, bt, mergeFn) { + const queue = [ + [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX] + ]; + do { + const Q = queue.length; + for (let q = 0; q < Q; ++q) { + let [at2, ai, bt2, bi] = queue[q]; + const bvt = tries[bt2][bi + TRIE_NODE_VALUE_ID_IDX]; + const bvi = tries[bt2][bi + TRIE_NODE_VALUE_IDX_IDX]; + if (bvt !== TRIE_NULL) { + const avt = tries[at2][ai + TRIE_NODE_VALUE_ID_IDX]; + const avi = tries[at2][ai + TRIE_NODE_VALUE_IDX_IDX]; + if (avt !== TRIE_NULL) { + mergeFn(avt, avi, bvt, bvi); + } else { + tries[at2][ai + TRIE_NODE_VALUE_ID_IDX] = bvt; + tries[at2][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi; + } + } + ai += TRIE_NODE_CHILDREN_IDX; + bi += TRIE_NODE_CHILDREN_IDX; + const bn = bi + TRIE_NODE_CHILDREN_LEN; + while (bi < bn) { + let ri = tries[bt2][bi + TRIE_CHILD_IDX_IDX]; + if (ri === TRIE_NULL) { + ai += TRIE_CHILD_LEN; + bi += TRIE_CHILD_LEN; + continue; + } + const rt = tries[bt2][ri + TRIE_NODE_ID_IDX]; + if (bt2 !== rt) { + ri = tries[bt2][ri + TRIE_RED_VALUE_IDX_IDX]; + } + let li = tries[at2][ai + TRIE_CHILD_IDX_IDX]; + if (li === TRIE_NULL) { + li = tries[at2][TRIE_SIZE_IDX]; + if (li + TRIE_RED_LEN > tries[at2].length) { + tries[at2] = grow(tries[at2], li + TRIE_RED_LEN); + } + tries[at2][TRIE_SIZE_IDX] += TRIE_RED_LEN; + tries[at2][li + TRIE_RED_ID_IDX] = rt; + tries[at2][li + TRIE_RED_VALUE_IDX_IDX] = ri; + } else { + const lt = tries[at2][li + TRIE_NODE_ID_IDX]; + if (at2 !== lt) { + ai = tries[at2][li + TRIE_RED_VALUE_IDX_IDX]; + } + queue.push([lt, li, rt, ri]); + } + ai += TRIE_CHILD_LEN; + bi += TRIE_CHILD_LEN; + } + } + queue.splice(0, Q); + } while (queue.length > 0); +} +function print(tries, key, trieIndex, stream, separator = "", callbackFn) { + const stack = new Array(key.length + 1); + stack[0] = [trieIndex, 0, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX]; + let top = 0; + let tail = false; + do { + let [trieI, childKey, childPtr] = stack[top]; + if (childKey >= TRIE_MAX_CHILDREN) { + --top; + continue; + } + ++stack[top][1]; + stack[top][2] += TRIE_CHILD_LEN; + if (childKey === 0) { + const nodeIndex = childPtr - TRIE_NODE_CHILDREN_IDX; + const valueId = tries[trieI][nodeIndex + TRIE_NODE_VALUE_ID_IDX]; + if (valueId !== TRIE_NULL) { + if (tail) { + stream.write(separator); + } + tail = true; + const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX]; + callbackFn(stream, key, top, valueId, valueIndex); + } + } + let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX]; + if (childI !== TRIE_NULL) { + const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX]; + if (trieI !== childTrieI) { + childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX]; + trieI = childTrieI; + } + key[top] = childKey + UTF8_PRINT_OFFSET; + stack[++top] = [trieI, 0, childI + TRIE_NODE_CHILDREN_IDX]; + } + } while (top >= 0); +} + +async function run$1(filePath, workerPath, maxWorkers) { + maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS); + const chunks = await getFileChunks( + filePath, + maxWorkers, + ENTRY_MAX_LEN, + CHUNK_SIZE_MIN + ); + maxWorkers = chunks.length; + const counts = new Array(maxWorkers + 1); + const maxes = new Array(maxWorkers + 1); + const mins = new Array(maxWorkers + 1); + const sums = new Array(maxWorkers + 1); + const tries = new Array(maxWorkers + 1); + const workers = new Array(maxWorkers); + for (let i = 0; i < maxWorkers; ++i) { + const worker = new node_worker_threads.Worker(workerPath); + worker.on("error", (err) => { + throw err; + }); + worker.on("messageerror", (err) => { + throw err; + }); + worker.on("exit", (code) => { + if (code > 1 || code < 0) { + throw new Error(`Worker ${worker.threadId} exited with code ${code}`); + } + }); + workers[i] = worker; + } + const tasks = new Array(maxWorkers); + for (let i = 0; i < maxWorkers; ++i) { + const id = i + 1; + const worker = workers[i]; + const [start, end] = chunks[i]; + tasks[i] = new Promise((resolve) => { + worker.once("message", resolve); + worker.postMessage({ end, filePath, id, start }); + }); + } + for await (const res of tasks) { + const id = res.id; + counts[id] = res.counts; + maxes[id] = res.maxes; + mins[id] = res.mins; + sums[id] = res.sums; + tries[id] = res.trie; + } + for (let i = 0; i < maxWorkers; ++i) { + await workers[i].terminate(); + } + for (let i = 2; i <= maxWorkers; ++i) { + mergeLeft(tries, 1, i, mergeStations); + } + const out = node_fs.createWriteStream("", { + flags: "a", + fd: 1, + highWaterMark: HIGH_WATER_MARK_OUT + }); + const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN); + out.write("{"); + print(tries, buffer, 1, out, ", ", printStation); + out.end("}\n"); + function mergeStations(at, ai, bt, bi) { + counts[at][ai] += counts[bt][bi]; + maxes[at][ai] = Math.max(maxes[at][ai], maxes[bt][bi]); + mins[at][ai] = Math.min(mins[at][ai], mins[bt][bi]); + sums[at][ai] += sums[bt][bi]; + } + function printStation(stream, name, nameLen, vt, vi) { + const avg = Math.round(sums[vt][vi] / counts[vt][vi]); + stream.write(name.toString("utf8", 0, nameLen)); + stream.write("="); + stream.write((mins[vt][vi] / 10).toFixed(1)); + stream.write("/"); + stream.write((avg / 10).toFixed(1)); + stream.write("/"); + stream.write((maxes[vt][vi] / 10).toFixed(1)); + } +} + +async function run({ + end, + filePath, + id, + start +}) { + const counts = new Uint32Array(MAX_STATIONS); + const maxes = new Int16Array(MAX_STATIONS); + const mins = new Int16Array(MAX_STATIONS); + const sums = new Float64Array(MAX_STATIONS); + if (start >= end) { + return { id, trie: createTrie(id, 0), counts, maxes, mins, sums }; + } + let trie = createTrie(id); + let stations = 0; + const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN); + const stream = node_fs.createReadStream(filePath, { + start, + end: end - 1, + highWaterMark: getHighWaterMark(end - start) + }); + let bufI = 0; + let tempI = 0; + let leaf; + for await (const chunk of stream) { + const N = chunk.length; + for (let i = 0; i < N; ++i) { + if (chunk[i] === CHAR_SEMICOLON) { + tempI = bufI; + } else if (chunk[i] !== CHAR_NEWLINE) { + buffer[bufI++] = chunk[i]; + } else { + const tempV = parseDouble(buffer, tempI, bufI); + bufI = 0; + [trie, leaf] = add(trie, buffer, 0, tempI); + if (trie[leaf + TRIE_NODE_VALUE_ID_IDX] !== TRIE_NULL) { + updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV); + } else { + trie[leaf + TRIE_NODE_VALUE_ID_IDX] = id; + trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations; + newStation(stations++, tempV); + } + } + } + } + function newStation(index, temp) { + counts[index] = 1; + maxes[index] = temp; + mins[index] = temp; + sums[index] = temp; + } + function updateStation(index, temp) { + ++counts[index]; + maxes[index] = maxes[index] >= temp ? maxes[index] : temp; + mins[index] = mins[index] <= temp ? mins[index] : temp; + sums[index] += temp; + } + return { id, trie, counts, maxes, mins, sums }; +} +function parseDouble(b, min, max) { + if (b[min] === CHAR_MINUS) { + return ++min + 4 > max ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11) : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111); + } + return min + 4 > max ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11 : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111; +} + +if (node_worker_threads.isMainThread) { + const workerPath = node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))); + run$1(process.argv[2], workerPath, os.availableParallelism()); +} else { + node_worker_threads.parentPort.addListener("message", async (req) => { + const res = await run(req); + node_worker_threads.parentPort.postMessage(res, [ + res.trie.buffer, + res.counts.buffer, + res.maxes.buffer, + res.mins.buffer, + res.sums.buffer + ]); + }); +} +//# sourceMappingURL=index.cjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs.map b/src/main/nodejs/havelessbemore/dist/index.cjs.map new file mode 100644 index 0000000..948663e --- /dev/null +++ b/src/main/nodejs/havelessbemore/dist/index.cjs.map @@ -0,0 +1 @@ +{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/trie.ts","../src/utils/trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n/**\n * The maximum value of a byte for UTF-8 code points of up to 2 bytes.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_2B_MAX = 224;\n\n/**\n * The number of non-printable control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_PRINT_OFFSET = 32;\n\n/**\n * The number of printable byte values for UTF-8 code points of up to 2 bytes.\n */\nexport const UTF8_2B_PRINT_MAX = UTF8_2B_MAX - UTF8_PRINT_OFFSET;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_2B_PRINT_MAX } from \"./utf8\";\n\n// Trie static properties\n\n/**\n * Represents null / undefined.\n */\nexport const TRIE_NULL = 0;\n\n/**\n * The minimum size a trie.\n */\nexport const MIN_TRIE_SIZE = 524288; // 2 MiB\n\n/**\n * The default growth factor for growing the size of a trie.\n */\nexport const TRIE_GROWTH_FACTOR = 1.618; // ~phi\n\n/**\n * All trie properties are represented by 32 bits (4 bytes).\n */\nexport const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT;\n\n/**\n * The maximum number of children of any trie node.\n */\nexport const TRIE_MAX_CHILDREN = UTF8_2B_PRINT_MAX;\n\n// Trie child pointer properties\n\nexport const TRIE_CHILD_IDX_IDX = 0;\nexport const TRIE_CHILD_IDX_LEN = 1;\n\nexport const TRIE_CHILD_LEN = TRIE_CHILD_IDX_LEN;\n\n// Trie redirect pointer properties\n\nexport const TRIE_RED_ID_IDX = 0;\nexport const TRIE_RED_ID_LEN = 1;\n\nexport const TRIE_RED_VALUE_IDX_IDX = 1;\nexport const TRIE_RED_VALUE_IDX_LEN = 1;\n\nexport const TRIE_RED_LEN = TRIE_RED_ID_LEN + TRIE_RED_VALUE_IDX_LEN;\n\n// Trie node properties\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_LEN = 1;\n\nexport const TRIE_NODE_VALUE_ID_IDX = 1;\nexport const TRIE_NODE_VALUE_ID_LEN = 1;\n\nexport const TRIE_NODE_VALUE_IDX_IDX = 2;\nexport const TRIE_NODE_VALUE_IDX_LEN = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 3;\nexport const TRIE_NODE_CHILDREN_LEN = TRIE_CHILD_LEN * TRIE_MAX_CHILDREN;\n\nexport const TRIE_NODE_LEN =\n TRIE_NODE_ID_LEN +\n TRIE_NODE_VALUE_ID_LEN +\n TRIE_NODE_VALUE_IDX_LEN +\n TRIE_NODE_CHILDREN_LEN;\n\n// Trie properties\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_LEN = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_LEN = TRIE_NODE_LEN;\n\nexport const TRIE_HEADER_LEN = TRIE_SIZE_LEN + TRIE_ROOT_LEN;\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n MIN_TRIE_SIZE,\n TRIE_CHILD_LEN,\n TRIE_CHILD_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_HEADER_LEN,\n TRIE_ID_IDX,\n TRIE_MAX_CHILDREN,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_CHILDREN_LEN,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_LEN,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NODE_VALUE_ID_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_RED_LEN,\n TRIE_RED_VALUE_IDX_IDX,\n TRIE_RED_ID_IDX,\n} from \"../constants/trie\";\nimport { UTF8_PRINT_OFFSET } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX +\n TRIE_CHILD_LEN * (key[min++] - UTF8_PRINT_OFFSET);\n let child = trie[index + TRIE_CHILD_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_LEN > trie.length) {\n trie = grow(trie, child + TRIE_NODE_LEN);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_LEN;\n // Attach and initialize node\n trie[index + TRIE_CHILD_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array {\n const minSize = TRIE_HEADER_LEN;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (at: number, ai: number, bt: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvt = tries[bt][bi + TRIE_NODE_VALUE_ID_IDX];\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX];\n if (bvt !== TRIE_NULL) {\n // If left value is not null\n const avt = tries[at][ai + TRIE_NODE_VALUE_ID_IDX];\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX];\n if (avt !== TRIE_NULL) {\n mergeFn(avt, avi, bvt, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_ID_IDX] = bvt;\n tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_LEN;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_CHILD_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_RED_LEN > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_RED_LEN);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_RED_LEN;\n // Add new redirect\n tries[at][li + TRIE_RED_ID_IDX] = rt;\n tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n id: number,\n value: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, 0, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childKey, childPtr] = stack[top];\n\n // Check if end of children array\n if (childKey >= TRIE_MAX_CHILDREN) {\n --top;\n continue;\n }\n\n // Update stack top\n ++stack[top][1];\n stack[top][2] += TRIE_CHILD_LEN;\n\n // If just reached node\n if (childKey === 0) {\n // Check if the node has a value\n const nodeIndex = childPtr - TRIE_NODE_CHILDREN_IDX;\n const valueId = tries[trieI][nodeIndex + TRIE_NODE_VALUE_ID_IDX];\n if (valueId !== TRIE_NULL) {\n // Print the node's value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX];\n callbackFn(stream, key, top, valueId, valueIndex);\n }\n }\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX];\n if (childI !== TRIE_NULL) {\n // Resolve child if redirect\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX];\n trieI = childTrieI;\n }\n // Add the child to the stack\n key[top] = childKey + UTF8_PRINT_OFFSET;\n stack[++top] = [trieI, 0, childI + TRIE_NODE_CHILDREN_IDX];\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { ENTRY_MAX_LEN, STATION_NAME_MAX_LEN } from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/trie\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const counts: Uint32Array[] = new Array(maxWorkers + 1);\n const maxes: Int16Array[] = new Array(maxWorkers + 1);\n const mins: Int16Array[] = new Array(maxWorkers + 1);\n const sums: Float64Array[] = new Array(maxWorkers + 1);\n const tries: Int32Array[] = new Array(maxWorkers + 1);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i + 1;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({ end, filePath, id, start } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n const id = res.id;\n counts[id] = res.counts;\n maxes[id] = res.maxes;\n mins[id] = res.mins;\n sums[id] = res.sums;\n tries[id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 2; i <= maxWorkers; ++i) {\n mergeLeft(tries, 1, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(\"\", {\n flags: \"a\",\n fd: 1,\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 1, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(at: number, ai: number, bt: number, bi: number): void {\n counts[at][ai] += counts[bt][bi];\n maxes[at][ai] = Math.max(maxes[at][ai], maxes[bt][bi]);\n mins[at][ai] = Math.min(mins[at][ai], mins[bt][bi]);\n sums[at][ai] += sums[bt][bi];\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vt: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vt][vi] / counts[vt][vi]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vt][vi] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vt][vi] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport {\n TRIE_NODE_VALUE_ID_IDX,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NULL,\n} from \"./constants/trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n}: WorkerRequest): Promise {\n const counts = new Uint32Array(MAX_STATIONS);\n const maxes = new Int16Array(MAX_STATIONS);\n const mins = new Int16Array(MAX_STATIONS);\n const sums = new Float64Array(MAX_STATIONS);\n\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0), counts, maxes, mins, sums };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = 0;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_ID_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_ID_IDX] = id;\n trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n counts[index] = 1;\n maxes[index] = temp;\n mins[index] = temp;\n sums[index] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n ++counts[index];\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n sums[index] += temp;\n }\n\n return { id, trie, counts, maxes, mins, sums };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n return ++min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import os from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, os.availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [\n res.trie.buffer,\n res.counts.buffer,\n res.maxes.buffer,\n res.mins.buffer,\n res.sums.buffer,\n ]);\n });\n}\n"],"names":["open","at","bt","run","Worker","createWriteStream","createReadStream","isMainThread","fileURLToPath","runMain","parentPort","runWorker"],"mappings":";;;;;;;;;AAQO,MAAM,YAAe,GAAA,GAAA,CAAA;AAKrB,MAAM,oBAAuB,GAAA,GAAA,CAAA;AAW7B,MAAM,aAAgB,GAAA,GAAA;;ACrBtB,MAAM,UAAa,GAAA,EAAA,CAAA;AAKnB,MAAM,YAAe,GAAA,EAAA,CAAA;AAUrB,MAAM,cAAiB,GAAA,EAAA,CAAA;AAKvB,MAAM,SAAY,GAAA,EAAA,CAAA;AAOlB,MAAM,WAAc,GAAA,GAAA,CAAA;AAOpB,MAAM,iBAAoB,GAAA,EAAA,CAAA;AAK1B,MAAM,oBAAoB,WAAc,GAAA,iBAAA;;ACrCxC,MAAM,mBAAsB,GAAA,KAAA,CAAA;AAK5B,MAAM,mBAAsB,GAAA,OAAA,CAAA;AAK5B,MAAM,mBAAsB,GAAA,OAAA,CAAA;AAM5B,MAAM,qBAAwB,GAAA,MAAA,CAAA;AAK9B,MAAM,cAAiB,GAAA,mBAAA,CAAA;AAOvB,MAAM,eAAe,EAAK,GAAA,SAAA,CAAA;AAK1B,MAAM,gBAAgB,GAAM,GAAA,SAAA;;ACnC5B,MAAM,WAAc,GAAA,CAAA,CAAA;AAKpB,MAAM,WAAc,GAAA,GAAA;;ACUX,SAAA,KAAA,CAAM,KAAe,EAAA,GAAA,EAAa,GAAqB,EAAA;AACrE,EAAA,OAAO,KAAQ,GAAA,GAAA,GAAO,KAAS,IAAA,GAAA,GAAM,QAAQ,GAAO,GAAA,GAAA,CAAA;AACtD,CAAA;AAoBA,eAAsB,aACpB,CAAA,QAAA,EACA,MACA,EAAA,aAAA,EACA,UAAU,CACmB,EAAA;AAE7B,EAAM,MAAA,IAAA,GAAO,MAAMA,aAAA,CAAK,QAAQ,CAAA,CAAA;AAChC,EAAI,IAAA;AAEF,IAAA,MAAM,IAAQ,GAAA,CAAA,MAAM,IAAK,CAAA,IAAA,EAAQ,EAAA,IAAA,CAAA;AAEjC,IAAM,MAAA,SAAA,GAAY,KAAK,GAAI,CAAA,OAAA,EAAS,KAAK,KAAM,CAAA,IAAA,GAAO,MAAM,CAAC,CAAA,CAAA;AAE7D,IAAM,MAAA,MAAA,GAAS,MAAO,CAAA,WAAA,CAAY,aAAa,CAAA,CAAA;AAC/C,IAAA,MAAM,SAA6B,EAAC,CAAA;AAEpC,IAAA,IAAI,KAAQ,GAAA,CAAA,CAAA;AACZ,IAAA,KAAA,IAAS,GAAM,GAAA,SAAA,EAAW,GAAM,GAAA,IAAA,EAAM,OAAO,SAAW,EAAA;AAEtD,MAAA,MAAM,MAAM,MAAM,IAAA,CAAK,KAAK,MAAQ,EAAA,CAAA,EAAG,eAAe,GAAG,CAAA,CAAA;AAEzD,MAAM,MAAA,OAAA,GAAU,MAAO,CAAA,OAAA,CAAQ,YAAY,CAAA,CAAA;AAE3C,MAAA,IAAI,OAAW,IAAA,CAAA,IAAK,OAAU,GAAA,GAAA,CAAI,SAAW,EAAA;AAE3C,QAAA,GAAA,IAAO,OAAU,GAAA,CAAA,CAAA;AAEjB,QAAA,MAAA,CAAO,IAAK,CAAA,CAAC,KAAO,EAAA,GAAG,CAAC,CAAA,CAAA;AAExB,QAAQ,KAAA,GAAA,GAAA,CAAA;AAAA,OACV;AAAA,KACF;AAEA,IAAA,IAAI,QAAQ,IAAM,EAAA;AAChB,MAAA,MAAA,CAAO,IAAK,CAAA,CAAC,KAAO,EAAA,IAAI,CAAC,CAAA,CAAA;AAAA,KAC3B;AAEA,IAAO,OAAA,MAAA,CAAA;AAAA,GACP,SAAA;AAEA,IAAA,MAAM,KAAK,KAAM,EAAA,CAAA;AAAA,GACnB;AACF,CAAA;AASO,SAAS,iBAAiB,IAAsB,EAAA;AAErD,EAAQ,IAAA,IAAA,qBAAA,CAAA;AAER,EAAA,IAAA,GAAO,IAAK,CAAA,KAAA,CAAM,IAAK,CAAA,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA;AAEjC,EAAA,IAAA,GAAO,CAAK,IAAA,IAAA,CAAA;AAEZ,EAAO,OAAA,KAAA,CAAM,IAAM,EAAA,mBAAA,EAAqB,mBAAmB,CAAA,CAAA;AAC7D;;AC9FO,MAAM,SAAY,GAAA,CAAA,CAAA;AAKlB,MAAM,aAAgB,GAAA,MAAA,CAAA;AAKtB,MAAM,kBAAqB,GAAA,KAAA,CAAA;AAU3B,MAAM,iBAAoB,GAAA,iBAAA,CAAA;AAI1B,MAAM,kBAAqB,GAAA,CAAA,CAAA;AAC3B,MAAM,kBAAqB,GAAA,CAAA,CAAA;AAE3B,MAAM,cAAiB,GAAA,kBAAA,CAAA;AAIvB,MAAM,eAAkB,GAAA,CAAA,CAAA;AACxB,MAAM,eAAkB,GAAA,CAAA,CAAA;AAExB,MAAM,sBAAyB,GAAA,CAAA,CAAA;AAC/B,MAAM,sBAAyB,GAAA,CAAA,CAAA;AAE/B,MAAM,eAAe,eAAkB,GAAA,sBAAA,CAAA;AAIvC,MAAM,gBAAmB,GAAA,CAAA,CAAA;AACzB,MAAM,gBAAmB,GAAA,CAAA,CAAA;AAEzB,MAAM,sBAAyB,GAAA,CAAA,CAAA;AAC/B,MAAM,sBAAyB,GAAA,CAAA,CAAA;AAE/B,MAAM,uBAA0B,GAAA,CAAA,CAAA;AAChC,MAAM,uBAA0B,GAAA,CAAA,CAAA;AAEhC,MAAM,sBAAyB,GAAA,CAAA,CAAA;AAC/B,MAAM,yBAAyB,cAAiB,GAAA,iBAAA,CAAA;AAE1C,MAAA,aAAA,GACX,gBACA,GAAA,sBAAA,GACA,uBACA,GAAA,sBAAA,CAAA;AAIK,MAAM,aAAgB,GAAA,CAAA,CAAA;AACtB,MAAM,aAAgB,GAAA,CAAA,CAAA;AAEtB,MAAM,aAAgB,GAAA,CAAA,CAAA;AACtB,MAAM,aAAgB,GAAA,aAAA,CAAA;AAEtB,MAAM,kBAAkB,aAAgB,GAAA,aAAA,CAAA;AACxC,MAAM,cAAc,aAAgB,GAAA,gBAAA;;AClDpC,SAAS,GACd,CAAA,IAAA,EACA,GACA,EAAA,GAAA,EACA,GACsB,EAAA;AACtB,EAAA,IAAI,KAAQ,GAAA,aAAA,CAAA;AACZ,EAAA,OAAO,MAAM,GAAK,EAAA;AAChB,IAAA,KAAA,IACE,sBACA,GAAA,cAAA,IAAkB,GAAI,CAAA,GAAA,EAAK,CAAI,GAAA,iBAAA,CAAA,CAAA;AACjC,IAAI,IAAA,KAAA,GAAQ,IAAK,CAAA,KAAA,GAAQ,kBAAkB,CAAA,CAAA;AAC3C,IAAA,IAAI,UAAU,SAAW,EAAA;AAEvB,MAAA,KAAA,GAAQ,KAAK,aAAa,CAAA,CAAA;AAC1B,MAAI,IAAA,KAAA,GAAQ,aAAgB,GAAA,IAAA,CAAK,MAAQ,EAAA;AACvC,QAAO,IAAA,GAAA,IAAA,CAAK,IAAM,EAAA,KAAA,GAAQ,aAAa,CAAA,CAAA;AAAA,OACzC;AACA,MAAA,IAAA,CAAK,aAAa,CAAK,IAAA,aAAA,CAAA;AAEvB,MAAK,IAAA,CAAA,KAAA,GAAQ,kBAAkB,CAAI,GAAA,KAAA,CAAA;AACnC,MAAA,IAAA,CAAK,KAAQ,GAAA,gBAAgB,CAAI,GAAA,IAAA,CAAK,WAAW,CAAA,CAAA;AAAA,KACnD;AACA,IAAQ,KAAA,GAAA,KAAA,CAAA;AAAA,GACV;AAEA,EAAO,OAAA,CAAC,MAAM,KAAK,CAAA,CAAA;AACrB,CAAA;AAEO,SAAS,UAAW,CAAA,EAAA,GAAK,CAAG,EAAA,IAAA,GAAO,aAA2B,EAAA;AACnE,EAAA,MAAM,OAAU,GAAA,eAAA,CAAA;AAChB,EAAA,MAAM,OAAO,IAAI,UAAA,CAAW,KAAK,GAAI,CAAA,OAAA,EAAS,IAAI,CAAC,CAAA,CAAA;AACnD,EAAA,IAAA,CAAK,aAAa,CAAI,GAAA,OAAA,CAAA;AACtB,EAAA,IAAA,CAAK,WAAW,CAAI,GAAA,EAAA,CAAA;AACpB,EAAO,OAAA,IAAA,CAAA;AACT,CAAA;AAEgB,SAAA,IAAA,CAAK,IAAkB,EAAA,OAAA,GAAU,CAAe,EAAA;AAC9D,EAAM,MAAA,MAAA,GAAS,KAAK,aAAa,CAAA,CAAA;AACjC,EAAA,OAAA,GAAU,KAAK,GAAI,CAAA,OAAA,EAAS,KAAK,IAAK,CAAA,MAAA,GAAS,kBAAkB,CAAC,CAAA,CAAA;AAClE,EAAM,MAAA,IAAA,GAAO,IAAI,UAAA,CAAW,OAAO,CAAA,CAAA;AACnC,EAAA,KAAA,IAAS,CAAI,GAAA,CAAA,EAAG,CAAI,GAAA,MAAA,EAAQ,EAAE,CAAG,EAAA;AAC/B,IAAK,IAAA,CAAA,CAAC,CAAI,GAAA,IAAA,CAAK,CAAC,CAAA,CAAA;AAAA,GAClB;AACA,EAAO,OAAA,IAAA,CAAA;AACT,CAAA;AAEO,SAAS,SACd,CAAA,KAAA,EACA,EACA,EAAA,EAAA,EACA,OACM,EAAA;AACN,EAAA,MAAM,KAA4C,GAAA;AAAA,IAChD,CAAC,EAAA,EAAI,aAAe,EAAA,EAAA,EAAI,aAAa,CAAA;AAAA,GACvC,CAAA;AAEA,EAAG,GAAA;AACD,IAAA,MAAM,IAAI,KAAM,CAAA,MAAA,CAAA;AAChB,IAAA,KAAA,IAAS,CAAI,GAAA,CAAA,EAAG,CAAI,GAAA,CAAA,EAAG,EAAE,CAAG,EAAA;AAC1B,MAAA,IAAI,CAACC,GAAI,EAAA,EAAA,EAAIC,KAAI,EAAE,CAAA,GAAI,MAAM,CAAC,CAAA,CAAA;AAG9B,MAAA,MAAM,GAAM,GAAA,KAAA,CAAMA,GAAE,CAAA,CAAE,KAAK,sBAAsB,CAAA,CAAA;AACjD,MAAA,MAAM,GAAM,GAAA,KAAA,CAAMA,GAAE,CAAA,CAAE,KAAK,uBAAuB,CAAA,CAAA;AAClD,MAAA,IAAI,QAAQ,SAAW,EAAA;AAErB,QAAA,MAAM,GAAM,GAAA,KAAA,CAAMD,GAAE,CAAA,CAAE,KAAK,sBAAsB,CAAA,CAAA;AACjD,QAAA,MAAM,GAAM,GAAA,KAAA,CAAMA,GAAE,CAAA,CAAE,KAAK,uBAAuB,CAAA,CAAA;AAClD,QAAA,IAAI,QAAQ,SAAW,EAAA;AACrB,UAAQ,OAAA,CAAA,GAAA,EAAK,GAAK,EAAA,GAAA,EAAK,GAAG,CAAA,CAAA;AAAA,SACrB,MAAA;AACL,UAAA,KAAA,CAAMA,GAAE,CAAA,CAAE,EAAK,GAAA,sBAAsB,CAAI,GAAA,GAAA,CAAA;AACzC,UAAA,KAAA,CAAMA,GAAE,CAAA,CAAE,EAAK,GAAA,uBAAuB,CAAI,GAAA,GAAA,CAAA;AAAA,SAC5C;AAAA,OACF;AAGA,MAAM,EAAA,IAAA,sBAAA,CAAA;AACN,MAAM,EAAA,IAAA,sBAAA,CAAA;AAGN,MAAA,MAAM,KAAK,EAAK,GAAA,sBAAA,CAAA;AAChB,MAAA,OAAO,KAAK,EAAI,EAAA;AAEd,QAAA,IAAI,EAAK,GAAA,KAAA,CAAMC,GAAE,CAAA,CAAE,KAAK,kBAAkB,CAAA,CAAA;AAC1C,QAAA,IAAI,OAAO,SAAW,EAAA;AAEpB,UAAM,EAAA,IAAA,cAAA,CAAA;AACN,UAAM,EAAA,IAAA,cAAA,CAAA;AACN,UAAA,SAAA;AAAA,SACF;AAGA,QAAA,MAAM,EAAK,GAAA,KAAA,CAAMA,GAAE,CAAA,CAAE,KAAK,gBAAgB,CAAA,CAAA;AAC1C,QAAA,IAAIA,QAAO,EAAI,EAAA;AACb,UAAA,EAAA,GAAK,KAAMA,CAAAA,GAAE,CAAE,CAAA,EAAA,GAAK,sBAAsB,CAAA,CAAA;AAAA,SAC5C;AAGA,QAAA,IAAI,EAAK,GAAA,KAAA,CAAMD,GAAE,CAAA,CAAE,KAAK,kBAAkB,CAAA,CAAA;AAC1C,QAAA,IAAI,OAAO,SAAW,EAAA;AAEpB,UAAK,EAAA,GAAA,KAAA,CAAMA,GAAE,CAAA,CAAE,aAAa,CAAA,CAAA;AAC5B,UAAA,IAAI,EAAK,GAAA,YAAA,GAAe,KAAMA,CAAAA,GAAE,EAAE,MAAQ,EAAA;AACxC,YAAA,KAAA,CAAMA,GAAE,CAAI,GAAA,IAAA,CAAK,MAAMA,GAAE,CAAA,EAAG,KAAK,YAAY,CAAA,CAAA;AAAA,WAC/C;AACA,UAAMA,KAAAA,CAAAA,GAAE,CAAE,CAAA,aAAa,CAAK,IAAA,YAAA,CAAA;AAE5B,UAAA,KAAA,CAAMA,GAAE,CAAA,CAAE,EAAK,GAAA,eAAe,CAAI,GAAA,EAAA,CAAA;AAClC,UAAA,KAAA,CAAMA,GAAE,CAAA,CAAE,EAAK,GAAA,sBAAsB,CAAI,GAAA,EAAA,CAAA;AAAA,SACpC,MAAA;AAEL,UAAA,MAAM,EAAK,GAAA,KAAA,CAAMA,GAAE,CAAA,CAAE,KAAK,gBAAgB,CAAA,CAAA;AAC1C,UAAA,IAAIA,QAAO,EAAI,EAAA;AACb,YAAA,EAAA,GAAK,KAAMA,CAAAA,GAAE,CAAE,CAAA,EAAA,GAAK,sBAAsB,CAAA,CAAA;AAAA,WAC5C;AAEA,UAAA,KAAA,CAAM,KAAK,CAAC,EAAA,EAAI,EAAI,EAAA,EAAA,EAAI,EAAE,CAAC,CAAA,CAAA;AAAA,SAC7B;AAGA,QAAM,EAAA,IAAA,cAAA,CAAA;AACN,QAAM,EAAA,IAAA,cAAA,CAAA;AAAA,OACR;AAAA,KACF;AACA,IAAM,KAAA,CAAA,MAAA,CAAO,GAAG,CAAC,CAAA,CAAA;AAAA,GACnB,QAAS,MAAM,MAAS,GAAA,CAAA,EAAA;AAC1B,CAAA;AAEO,SAAS,MACd,KACA,EAAA,GAAA,EACA,WACA,MACA,EAAA,SAAA,GAAY,IACZ,UAOM,EAAA;AACN,EAAA,MAAM,KAAoC,GAAA,IAAI,KAAM,CAAA,GAAA,CAAI,SAAS,CAAC,CAAA,CAAA;AAClE,EAAA,KAAA,CAAM,CAAC,CAAI,GAAA,CAAC,SAAW,EAAA,CAAA,EAAG,gBAAgB,sBAAsB,CAAA,CAAA;AAEhE,EAAA,IAAI,GAAM,GAAA,CAAA,CAAA;AACV,EAAA,IAAI,IAAO,GAAA,KAAA,CAAA;AACX,EAAG,GAAA;AACD,IAAA,IAAI,CAAC,KAAO,EAAA,QAAA,EAAU,QAAQ,CAAA,GAAI,MAAM,GAAG,CAAA,CAAA;AAG3C,IAAA,IAAI,YAAY,iBAAmB,EAAA;AACjC,MAAE,EAAA,GAAA,CAAA;AACF,MAAA,SAAA;AAAA,KACF;AAGA,IAAE,EAAA,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,CAAA,CAAA;AACd,IAAM,KAAA,CAAA,GAAG,CAAE,CAAA,CAAC,CAAK,IAAA,cAAA,CAAA;AAGjB,IAAA,IAAI,aAAa,CAAG,EAAA;AAElB,MAAA,MAAM,YAAY,QAAW,GAAA,sBAAA,CAAA;AAC7B,MAAA,MAAM,OAAU,GAAA,KAAA,CAAM,KAAK,CAAA,CAAE,YAAY,sBAAsB,CAAA,CAAA;AAC/D,MAAA,IAAI,YAAY,SAAW,EAAA;AAEzB,QAAA,IAAI,IAAM,EAAA;AACR,UAAA,MAAA,CAAO,MAAM,SAAS,CAAA,CAAA;AAAA,SACxB;AACA,QAAO,IAAA,GAAA,IAAA,CAAA;AACP,QAAA,MAAM,UAAa,GAAA,KAAA,CAAM,KAAK,CAAA,CAAE,YAAY,uBAAuB,CAAA,CAAA;AACnE,QAAA,UAAA,CAAW,MAAQ,EAAA,GAAA,EAAK,GAAK,EAAA,OAAA,EAAS,UAAU,CAAA,CAAA;AAAA,OAClD;AAAA,KACF;AAGA,IAAA,IAAI,MAAS,GAAA,KAAA,CAAM,KAAK,CAAA,CAAE,WAAW,kBAAkB,CAAA,CAAA;AACvD,IAAA,IAAI,WAAW,SAAW,EAAA;AAExB,MAAA,MAAM,UAAa,GAAA,KAAA,CAAM,KAAK,CAAA,CAAE,SAAS,gBAAgB,CAAA,CAAA;AACzD,MAAA,IAAI,UAAU,UAAY,EAAA;AACxB,QAAA,MAAA,GAAS,KAAM,CAAA,KAAK,CAAE,CAAA,MAAA,GAAS,sBAAsB,CAAA,CAAA;AACrD,QAAQ,KAAA,GAAA,UAAA,CAAA;AAAA,OACV;AAEA,MAAI,GAAA,CAAA,GAAG,IAAI,QAAW,GAAA,iBAAA,CAAA;AACtB,MAAA,KAAA,CAAM,EAAE,GAAG,CAAA,GAAI,CAAC,KAAO,EAAA,CAAA,EAAG,SAAS,sBAAsB,CAAA,CAAA;AAAA,KAC3D;AAAA,WACO,GAAO,IAAA,CAAA,EAAA;AAClB;;AC7MsB,eAAAE,KAAA,CACpB,QACA,EAAA,UAAA,EACA,UACe,EAAA;AAEf,EAAa,UAAA,GAAA,KAAA,CAAM,UAAY,EAAA,WAAA,EAAa,WAAW,CAAA,CAAA;AAGvD,EAAA,MAAM,SAAS,MAAM,aAAA;AAAA,IACnB,QAAA;AAAA,IACA,UAAA;AAAA,IACA,aAAA;AAAA,IACA,cAAA;AAAA,GACF,CAAA;AAGA,EAAA,UAAA,GAAa,MAAO,CAAA,MAAA,CAAA;AAGpB,EAAA,MAAM,MAAwB,GAAA,IAAI,KAAM,CAAA,UAAA,GAAa,CAAC,CAAA,CAAA;AACtD,EAAA,MAAM,KAAsB,GAAA,IAAI,KAAM,CAAA,UAAA,GAAa,CAAC,CAAA,CAAA;AACpD,EAAA,MAAM,IAAqB,GAAA,IAAI,KAAM,CAAA,UAAA,GAAa,CAAC,CAAA,CAAA;AACnD,EAAA,MAAM,IAAuB,GAAA,IAAI,KAAM,CAAA,UAAA,GAAa,CAAC,CAAA,CAAA;AACrD,EAAA,MAAM,KAAsB,GAAA,IAAI,KAAM,CAAA,UAAA,GAAa,CAAC,CAAA,CAAA;AAGpD,EAAM,MAAA,OAAA,GAAU,IAAI,KAAA,CAAc,UAAU,CAAA,CAAA;AAC5C,EAAA,KAAA,IAAS,CAAI,GAAA,CAAA,EAAG,CAAI,GAAA,UAAA,EAAY,EAAE,CAAG,EAAA;AACnC,IAAM,MAAA,MAAA,GAAS,IAAIC,0BAAA,CAAO,UAAU,CAAA,CAAA;AACpC,IAAO,MAAA,CAAA,EAAA,CAAG,OAAS,EAAA,CAAC,GAAQ,KAAA;AAC1B,MAAM,MAAA,GAAA,CAAA;AAAA,KACP,CAAA,CAAA;AACD,IAAO,MAAA,CAAA,EAAA,CAAG,cAAgB,EAAA,CAAC,GAAQ,KAAA;AACjC,MAAM,MAAA,GAAA,CAAA;AAAA,KACP,CAAA,CAAA;AACD,IAAO,MAAA,CAAA,EAAA,CAAG,MAAQ,EAAA,CAAC,IAAS,KAAA;AAC1B,MAAI,IAAA,IAAA,GAAO,CAAK,IAAA,IAAA,GAAO,CAAG,EAAA;AACxB,QAAA,MAAM,IAAI,KAAM,CAAA,CAAA,OAAA,EAAU,OAAO,QAAQ,CAAA,kBAAA,EAAqB,IAAI,CAAE,CAAA,CAAA,CAAA;AAAA,OACtE;AAAA,KACD,CAAA,CAAA;AACD,IAAA,OAAA,CAAQ,CAAC,CAAI,GAAA,MAAA,CAAA;AAAA,GACf;AAGA,EAAM,MAAA,KAAA,GAAQ,IAAI,KAAA,CAA+B,UAAU,CAAA,CAAA;AAC3D,EAAA,KAAA,IAAS,CAAI,GAAA,CAAA,EAAG,CAAI,GAAA,UAAA,EAAY,EAAE,CAAG,EAAA;AACnC,IAAA,MAAM,KAAK,CAAI,GAAA,CAAA,CAAA;AACf,IAAM,MAAA,MAAA,GAAS,QAAQ,CAAC,CAAA,CAAA;AACxB,IAAA,MAAM,CAAC,KAAA,EAAO,GAAG,CAAA,GAAI,OAAO,CAAC,CAAA,CAAA;AAC7B,IAAA,KAAA,CAAM,CAAC,CAAA,GAAI,IAAI,OAAA,CAAQ,CAAC,OAAY,KAAA;AAClC,MAAO,MAAA,CAAA,IAAA,CAAK,WAAW,OAAO,CAAA,CAAA;AAC9B,MAAA,MAAA,CAAO,YAAY,EAAE,GAAA,EAAK,QAAU,EAAA,EAAA,EAAI,OAAwB,CAAA,CAAA;AAAA,KACjE,CAAA,CAAA;AAAA,GACH;AAGA,EAAA,WAAA,MAAiB,OAAO,KAAO,EAAA;AAC7B,IAAA,MAAM,KAAK,GAAI,CAAA,EAAA,CAAA;AACf,IAAO,MAAA,CAAA,EAAE,IAAI,GAAI,CAAA,MAAA,CAAA;AACjB,IAAM,KAAA,CAAA,EAAE,IAAI,GAAI,CAAA,KAAA,CAAA;AAChB,IAAK,IAAA,CAAA,EAAE,IAAI,GAAI,CAAA,IAAA,CAAA;AACf,IAAK,IAAA,CAAA,EAAE,IAAI,GAAI,CAAA,IAAA,CAAA;AACf,IAAM,KAAA,CAAA,EAAE,IAAI,GAAI,CAAA,IAAA,CAAA;AAAA,GAClB;AAGA,EAAA,KAAA,IAAS,CAAI,GAAA,CAAA,EAAG,CAAI,GAAA,UAAA,EAAY,EAAE,CAAG,EAAA;AACnC,IAAM,MAAA,OAAA,CAAQ,CAAC,CAAA,CAAE,SAAU,EAAA,CAAA;AAAA,GAC7B;AAGA,EAAA,KAAA,IAAS,CAAI,GAAA,CAAA,EAAG,CAAK,IAAA,UAAA,EAAY,EAAE,CAAG,EAAA;AACpC,IAAU,SAAA,CAAA,KAAA,EAAO,CAAG,EAAA,CAAA,EAAG,aAAa,CAAA,CAAA;AAAA,GACtC;AAGA,EAAM,MAAA,GAAA,GAAMC,0BAAkB,EAAI,EAAA;AAAA,IAChC,KAAO,EAAA,GAAA;AAAA,IACP,EAAI,EAAA,CAAA;AAAA,IACJ,aAAe,EAAA,mBAAA;AAAA,GAChB,CAAA,CAAA;AACD,EAAM,MAAA,MAAA,GAAS,MAAO,CAAA,WAAA,CAAY,oBAAoB,CAAA,CAAA;AACtD,EAAA,GAAA,CAAI,MAAM,GAAG,CAAA,CAAA;AACb,EAAA,KAAA,CAAM,KAAO,EAAA,MAAA,EAAQ,CAAG,EAAA,GAAA,EAAK,MAAM,YAAY,CAAA,CAAA;AAC/C,EAAA,GAAA,CAAI,IAAI,KAAK,CAAA,CAAA;AAEb,EAAA,SAAS,aAAc,CAAA,EAAA,EAAY,EAAY,EAAA,EAAA,EAAY,EAAkB,EAAA;AAC3E,IAAA,MAAA,CAAO,EAAE,CAAE,CAAA,EAAE,KAAK,MAAO,CAAA,EAAE,EAAE,EAAE,CAAA,CAAA;AAC/B,IAAA,KAAA,CAAM,EAAE,CAAA,CAAE,EAAE,CAAA,GAAI,KAAK,GAAI,CAAA,KAAA,CAAM,EAAE,CAAA,CAAE,EAAE,CAAG,EAAA,KAAA,CAAM,EAAE,CAAA,CAAE,EAAE,CAAC,CAAA,CAAA;AACrD,IAAA,IAAA,CAAK,EAAE,CAAA,CAAE,EAAE,CAAA,GAAI,KAAK,GAAI,CAAA,IAAA,CAAK,EAAE,CAAA,CAAE,EAAE,CAAG,EAAA,IAAA,CAAK,EAAE,CAAA,CAAE,EAAE,CAAC,CAAA,CAAA;AAClD,IAAA,IAAA,CAAK,EAAE,CAAE,CAAA,EAAE,KAAK,IAAK,CAAA,EAAE,EAAE,EAAE,CAAA,CAAA;AAAA,GAC7B;AAEA,EAAA,SAAS,YACP,CAAA,MAAA,EACA,IACA,EAAA,OAAA,EACA,IACA,EACM,EAAA;AACN,IAAA,MAAM,GAAM,GAAA,IAAA,CAAK,KAAM,CAAA,IAAA,CAAK,EAAE,CAAA,CAAE,EAAE,CAAA,GAAI,MAAO,CAAA,EAAE,CAAE,CAAA,EAAE,CAAC,CAAA,CAAA;AACpD,IAAA,MAAA,CAAO,MAAM,IAAK,CAAA,QAAA,CAAS,MAAQ,EAAA,CAAA,EAAG,OAAO,CAAC,CAAA,CAAA;AAC9C,IAAA,MAAA,CAAO,MAAM,GAAG,CAAA,CAAA;AAChB,IAAO,MAAA,CAAA,KAAA,CAAA,CAAO,KAAK,EAAE,CAAA,CAAE,EAAE,CAAI,GAAA,EAAA,EAAI,OAAQ,CAAA,CAAC,CAAC,CAAA,CAAA;AAC3C,IAAA,MAAA,CAAO,MAAM,GAAG,CAAA,CAAA;AAChB,IAAA,MAAA,CAAO,KAAO,CAAA,CAAA,GAAA,GAAM,EAAI,EAAA,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAA;AAClC,IAAA,MAAA,CAAO,MAAM,GAAG,CAAA,CAAA;AAChB,IAAO,MAAA,CAAA,KAAA,CAAA,CAAO,MAAM,EAAE,CAAA,CAAE,EAAE,CAAI,GAAA,EAAA,EAAI,OAAQ,CAAA,CAAC,CAAC,CAAA,CAAA;AAAA,GAC9C;AACF;;ACxGA,eAAsB,GAAI,CAAA;AAAA,EACxB,GAAA;AAAA,EACA,QAAA;AAAA,EACA,EAAA;AAAA,EACA,KAAA;AACF,CAA2C,EAAA;AACzC,EAAM,MAAA,MAAA,GAAS,IAAI,WAAA,CAAY,YAAY,CAAA,CAAA;AAC3C,EAAM,MAAA,KAAA,GAAQ,IAAI,UAAA,CAAW,YAAY,CAAA,CAAA;AACzC,EAAM,MAAA,IAAA,GAAO,IAAI,UAAA,CAAW,YAAY,CAAA,CAAA;AACxC,EAAM,MAAA,IAAA,GAAO,IAAI,YAAA,CAAa,YAAY,CAAA,CAAA;AAG1C,EAAA,IAAI,SAAS,GAAK,EAAA;AAChB,IAAO,OAAA,EAAE,EAAI,EAAA,IAAA,EAAM,UAAW,CAAA,EAAA,EAAI,CAAC,CAAG,EAAA,MAAA,EAAQ,KAAO,EAAA,IAAA,EAAM,IAAK,EAAA,CAAA;AAAA,GAClE;AAGA,EAAI,IAAA,IAAA,GAAO,WAAW,EAAE,CAAA,CAAA;AACxB,EAAA,IAAI,QAAW,GAAA,CAAA,CAAA;AACf,EAAM,MAAA,MAAA,GAAS,MAAO,CAAA,WAAA,CAAY,aAAa,CAAA,CAAA;AAG/C,EAAM,MAAA,MAAA,GAASC,yBAAiB,QAAU,EAAA;AAAA,IACxC,KAAA;AAAA,IACA,KAAK,GAAM,GAAA,CAAA;AAAA,IACX,aAAA,EAAe,gBAAiB,CAAA,GAAA,GAAM,KAAK,CAAA;AAAA,GAC5C,CAAA,CAAA;AAGD,EAAA,IAAI,IAAO,GAAA,CAAA,CAAA;AACX,EAAA,IAAI,KAAQ,GAAA,CAAA,CAAA;AACZ,EAAI,IAAA,IAAA,CAAA;AACJ,EAAA,WAAA,MAAiB,SAAS,MAAQ,EAAA;AAEhC,IAAA,MAAM,IAAI,KAAM,CAAA,MAAA,CAAA;AAChB,IAAA,KAAA,IAAS,CAAI,GAAA,CAAA,EAAG,CAAI,GAAA,CAAA,EAAG,EAAE,CAAG,EAAA;AAC1B,MAAI,IAAA,KAAA,CAAM,CAAC,CAAA,KAAM,cAAgB,EAAA;AAE/B,QAAQ,KAAA,GAAA,IAAA,CAAA;AAAA,OACC,MAAA,IAAA,KAAA,CAAM,CAAC,CAAA,KAAM,YAAc,EAAA;AAEpC,QAAO,MAAA,CAAA,IAAA,EAAM,CAAI,GAAA,KAAA,CAAM,CAAC,CAAA,CAAA;AAAA,OACnB,MAAA;AAEL,QAAA,MAAM,KAAQ,GAAA,WAAA,CAAY,MAAQ,EAAA,KAAA,EAAO,IAAI,CAAA,CAAA;AAC7C,QAAO,IAAA,GAAA,CAAA,CAAA;AAEP,QAAA,CAAC,MAAM,IAAI,CAAA,GAAI,IAAI,IAAM,EAAA,MAAA,EAAQ,GAAG,KAAK,CAAA,CAAA;AAEzC,QAAA,IAAI,IAAK,CAAA,IAAA,GAAO,sBAAsB,CAAA,KAAM,SAAW,EAAA;AAErD,UAAA,aAAA,CAAc,IAAK,CAAA,IAAA,GAAO,uBAAuB,CAAA,EAAG,KAAK,CAAA,CAAA;AAAA,SACpD,MAAA;AAEL,UAAK,IAAA,CAAA,IAAA,GAAO,sBAAsB,CAAI,GAAA,EAAA,CAAA;AACtC,UAAK,IAAA,CAAA,IAAA,GAAO,uBAAuB,CAAI,GAAA,QAAA,CAAA;AACvC,UAAA,UAAA,CAAW,YAAY,KAAK,CAAA,CAAA;AAAA,SAC9B;AAAA,OACF;AAAA,KACF;AAAA,GACF;AAEA,EAAS,SAAA,UAAA,CAAW,OAAe,IAAoB,EAAA;AACrD,IAAA,MAAA,CAAO,KAAK,CAAI,GAAA,CAAA,CAAA;AAChB,IAAA,KAAA,CAAM,KAAK,CAAI,GAAA,IAAA,CAAA;AACf,IAAA,IAAA,CAAK,KAAK,CAAI,GAAA,IAAA,CAAA;AACd,IAAA,IAAA,CAAK,KAAK,CAAI,GAAA,IAAA,CAAA;AAAA,GAChB;AAEA,EAAS,SAAA,aAAA,CAAc,OAAe,IAAoB,EAAA;AACxD,IAAA,EAAE,OAAO,KAAK,CAAA,CAAA;AACd,IAAM,KAAA,CAAA,KAAK,IAAI,KAAM,CAAA,KAAK,KAAK,IAAO,GAAA,KAAA,CAAM,KAAK,CAAI,GAAA,IAAA,CAAA;AACrD,IAAK,IAAA,CAAA,KAAK,IAAI,IAAK,CAAA,KAAK,KAAK,IAAO,GAAA,IAAA,CAAK,KAAK,CAAI,GAAA,IAAA,CAAA;AAClD,IAAA,IAAA,CAAK,KAAK,CAAK,IAAA,IAAA,CAAA;AAAA,GACjB;AAEA,EAAA,OAAO,EAAE,EAAI,EAAA,IAAA,EAAM,MAAQ,EAAA,KAAA,EAAO,MAAM,IAAK,EAAA,CAAA;AAC/C,CAAA;AAEgB,SAAA,WAAA,CAAY,CAAW,EAAA,GAAA,EAAa,GAAqB,EAAA;AACvE,EAAI,IAAA,CAAA,CAAE,GAAG,CAAA,KAAM,UAAY,EAAA;AACzB,IAAO,OAAA,EAAE,GAAM,GAAA,CAAA,GAAI,GACf,GAAA,EAAE,EAAK,GAAA,CAAA,CAAE,GAAG,CAAA,GAAI,CAAE,CAAA,GAAA,GAAM,CAAC,CAAA,GAAI,YAC7B,CAAA,GAAA,EAAE,GAAM,GAAA,CAAA,CAAE,GAAG,CAAA,GAAI,EAAK,GAAA,CAAA,CAAE,GAAM,GAAA,CAAC,CAAI,GAAA,CAAA,CAAE,GAAM,GAAA,CAAC,CAAI,GAAA,aAAA,CAAA,CAAA;AAAA,GACtD;AACA,EAAO,OAAA,GAAA,GAAM,CAAI,GAAA,GAAA,GACb,EAAK,GAAA,CAAA,CAAE,GAAG,CAAI,GAAA,CAAA,CAAE,GAAM,GAAA,CAAC,CAAI,GAAA,YAAA,GAC3B,MAAM,CAAE,CAAA,GAAG,CAAI,GAAA,EAAA,GAAK,CAAE,CAAA,GAAA,GAAM,CAAC,CAAI,GAAA,CAAA,CAAE,GAAM,GAAA,CAAC,CAAI,GAAA,aAAA,CAAA;AACpD;;ACjGA,IAAIC,gCAAc,EAAA;AAChB,EAAM,MAAA,UAAA,GAAaC,sBAAc,CAAA,8LAAe,CAAA,CAAA;AAChD,EAAAC,KAAA,CAAQ,QAAQ,IAAK,CAAA,CAAC,GAAG,UAAY,EAAA,EAAA,CAAG,sBAAsB,CAAA,CAAA;AAChE,CAAO,MAAA;AACL,EAAYC,8BAAA,CAAA,WAAA,CAAY,SAAW,EAAA,OAAO,GAAuB,KAAA;AAC/D,IAAM,MAAA,GAAA,GAAM,MAAMC,GAAA,CAAU,GAAG,CAAA,CAAA;AAC/B,IAAAD,8BAAA,CAAY,YAAY,GAAK,EAAA;AAAA,MAC3B,IAAI,IAAK,CAAA,MAAA;AAAA,MACT,IAAI,MAAO,CAAA,MAAA;AAAA,MACX,IAAI,KAAM,CAAA,MAAA;AAAA,MACV,IAAI,IAAK,CAAA,MAAA;AAAA,MACT,IAAI,IAAK,CAAA,MAAA;AAAA,KACV,CAAA,CAAA;AAAA,GACF,CAAA,CAAA;AACH;;"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs new file mode 100644 index 0000000..ea363d7 --- /dev/null +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -0,0 +1,384 @@ +import os from 'node:os'; +import { fileURLToPath } from 'node:url'; +import { Worker, isMainThread, parentPort } from 'node:worker_threads'; +import { createWriteStream, createReadStream } from 'node:fs'; +import { open } from 'fs/promises'; + +const MAX_STATIONS = 1e4; +const STATION_NAME_MAX_LEN = 100; +const ENTRY_MAX_LEN = 107; + +const CHAR_MINUS = 45; +const CHAR_NEWLINE = 10; +const CHAR_SEMICOLON = 59; +const CHAR_ZERO = 48; +const UTF8_2B_MAX = 224; +const UTF8_PRINT_OFFSET = 32; +const UTF8_2B_PRINT_MAX = UTF8_2B_MAX - UTF8_PRINT_OFFSET; + +const HIGH_WATER_MARK_MIN = 16384; +const HIGH_WATER_MARK_MAX = 1048576; +const HIGH_WATER_MARK_OUT = 1048576; +const HIGH_WATER_MARK_RATIO = 152e-6; +const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN; +const CHAR_ZERO_11 = 11 * CHAR_ZERO; +const CHAR_ZERO_111 = 111 * CHAR_ZERO; + +const MIN_WORKERS = 1; +const MAX_WORKERS = 512; + +function clamp(value, min, max) { + return value > min ? value <= max ? value : max : min; +} +async function getFileChunks(filePath, target, maxLineLength, minSize = 0) { + const file = await open(filePath); + try { + const size = (await file.stat()).size; + const chunkSize = Math.max(minSize, Math.floor(size / target)); + const buffer = Buffer.allocUnsafe(maxLineLength); + const chunks = []; + let start = 0; + for (let end = chunkSize; end < size; end += chunkSize) { + const res = await file.read(buffer, 0, maxLineLength, end); + const newline = buffer.indexOf(CHAR_NEWLINE); + if (newline >= 0 && newline < res.bytesRead) { + end += newline + 1; + chunks.push([start, end]); + start = end; + } + } + if (start < size) { + chunks.push([start, size]); + } + return chunks; + } finally { + await file.close(); + } +} +function getHighWaterMark(size) { + size *= HIGH_WATER_MARK_RATIO; + size = Math.round(Math.log2(size)); + size = 2 ** size; + return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX); +} + +const TRIE_NULL = 0; +const MIN_TRIE_SIZE = 524288; +const TRIE_GROWTH_FACTOR = 1.618; +const TRIE_MAX_CHILDREN = UTF8_2B_PRINT_MAX; +const TRIE_CHILD_IDX_IDX = 0; +const TRIE_CHILD_IDX_LEN = 1; +const TRIE_CHILD_LEN = TRIE_CHILD_IDX_LEN; +const TRIE_RED_ID_IDX = 0; +const TRIE_RED_ID_LEN = 1; +const TRIE_RED_VALUE_IDX_IDX = 1; +const TRIE_RED_VALUE_IDX_LEN = 1; +const TRIE_RED_LEN = TRIE_RED_ID_LEN + TRIE_RED_VALUE_IDX_LEN; +const TRIE_NODE_ID_IDX = 0; +const TRIE_NODE_ID_LEN = 1; +const TRIE_NODE_VALUE_ID_IDX = 1; +const TRIE_NODE_VALUE_ID_LEN = 1; +const TRIE_NODE_VALUE_IDX_IDX = 2; +const TRIE_NODE_VALUE_IDX_LEN = 1; +const TRIE_NODE_CHILDREN_IDX = 3; +const TRIE_NODE_CHILDREN_LEN = TRIE_CHILD_LEN * TRIE_MAX_CHILDREN; +const TRIE_NODE_LEN = TRIE_NODE_ID_LEN + TRIE_NODE_VALUE_ID_LEN + TRIE_NODE_VALUE_IDX_LEN + TRIE_NODE_CHILDREN_LEN; +const TRIE_SIZE_IDX = 0; +const TRIE_SIZE_LEN = 1; +const TRIE_ROOT_IDX = 1; +const TRIE_ROOT_LEN = TRIE_NODE_LEN; +const TRIE_HEADER_LEN = TRIE_SIZE_LEN + TRIE_ROOT_LEN; +const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX; + +function add(trie, key, min, max) { + let index = TRIE_ROOT_IDX; + while (min < max) { + index += TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_LEN * (key[min++] - UTF8_PRINT_OFFSET); + let child = trie[index + TRIE_CHILD_IDX_IDX]; + if (child === TRIE_NULL) { + child = trie[TRIE_SIZE_IDX]; + if (child + TRIE_NODE_LEN > trie.length) { + trie = grow(trie, child + TRIE_NODE_LEN); + } + trie[TRIE_SIZE_IDX] += TRIE_NODE_LEN; + trie[index + TRIE_CHILD_IDX_IDX] = child; + trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX]; + } + index = child; + } + return [trie, index]; +} +function createTrie(id = 0, size = MIN_TRIE_SIZE) { + const minSize = TRIE_HEADER_LEN; + const trie = new Int32Array(Math.max(minSize, size)); + trie[TRIE_SIZE_IDX] = minSize; + trie[TRIE_ID_IDX] = id; + return trie; +} +function grow(trie, minSize = 0) { + const length = trie[TRIE_SIZE_IDX]; + minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR)); + const next = new Int32Array(minSize); + for (let i = 0; i < length; ++i) { + next[i] = trie[i]; + } + return next; +} +function mergeLeft(tries, at, bt, mergeFn) { + const queue = [ + [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX] + ]; + do { + const Q = queue.length; + for (let q = 0; q < Q; ++q) { + let [at2, ai, bt2, bi] = queue[q]; + const bvt = tries[bt2][bi + TRIE_NODE_VALUE_ID_IDX]; + const bvi = tries[bt2][bi + TRIE_NODE_VALUE_IDX_IDX]; + if (bvt !== TRIE_NULL) { + const avt = tries[at2][ai + TRIE_NODE_VALUE_ID_IDX]; + const avi = tries[at2][ai + TRIE_NODE_VALUE_IDX_IDX]; + if (avt !== TRIE_NULL) { + mergeFn(avt, avi, bvt, bvi); + } else { + tries[at2][ai + TRIE_NODE_VALUE_ID_IDX] = bvt; + tries[at2][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi; + } + } + ai += TRIE_NODE_CHILDREN_IDX; + bi += TRIE_NODE_CHILDREN_IDX; + const bn = bi + TRIE_NODE_CHILDREN_LEN; + while (bi < bn) { + let ri = tries[bt2][bi + TRIE_CHILD_IDX_IDX]; + if (ri === TRIE_NULL) { + ai += TRIE_CHILD_LEN; + bi += TRIE_CHILD_LEN; + continue; + } + const rt = tries[bt2][ri + TRIE_NODE_ID_IDX]; + if (bt2 !== rt) { + ri = tries[bt2][ri + TRIE_RED_VALUE_IDX_IDX]; + } + let li = tries[at2][ai + TRIE_CHILD_IDX_IDX]; + if (li === TRIE_NULL) { + li = tries[at2][TRIE_SIZE_IDX]; + if (li + TRIE_RED_LEN > tries[at2].length) { + tries[at2] = grow(tries[at2], li + TRIE_RED_LEN); + } + tries[at2][TRIE_SIZE_IDX] += TRIE_RED_LEN; + tries[at2][li + TRIE_RED_ID_IDX] = rt; + tries[at2][li + TRIE_RED_VALUE_IDX_IDX] = ri; + } else { + const lt = tries[at2][li + TRIE_NODE_ID_IDX]; + if (at2 !== lt) { + ai = tries[at2][li + TRIE_RED_VALUE_IDX_IDX]; + } + queue.push([lt, li, rt, ri]); + } + ai += TRIE_CHILD_LEN; + bi += TRIE_CHILD_LEN; + } + } + queue.splice(0, Q); + } while (queue.length > 0); +} +function print(tries, key, trieIndex, stream, separator = "", callbackFn) { + const stack = new Array(key.length + 1); + stack[0] = [trieIndex, 0, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX]; + let top = 0; + let tail = false; + do { + let [trieI, childKey, childPtr] = stack[top]; + if (childKey >= TRIE_MAX_CHILDREN) { + --top; + continue; + } + ++stack[top][1]; + stack[top][2] += TRIE_CHILD_LEN; + if (childKey === 0) { + const nodeIndex = childPtr - TRIE_NODE_CHILDREN_IDX; + const valueId = tries[trieI][nodeIndex + TRIE_NODE_VALUE_ID_IDX]; + if (valueId !== TRIE_NULL) { + if (tail) { + stream.write(separator); + } + tail = true; + const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX]; + callbackFn(stream, key, top, valueId, valueIndex); + } + } + let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX]; + if (childI !== TRIE_NULL) { + const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX]; + if (trieI !== childTrieI) { + childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX]; + trieI = childTrieI; + } + key[top] = childKey + UTF8_PRINT_OFFSET; + stack[++top] = [trieI, 0, childI + TRIE_NODE_CHILDREN_IDX]; + } + } while (top >= 0); +} + +async function run$1(filePath, workerPath, maxWorkers) { + maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS); + const chunks = await getFileChunks( + filePath, + maxWorkers, + ENTRY_MAX_LEN, + CHUNK_SIZE_MIN + ); + maxWorkers = chunks.length; + const counts = new Array(maxWorkers + 1); + const maxes = new Array(maxWorkers + 1); + const mins = new Array(maxWorkers + 1); + const sums = new Array(maxWorkers + 1); + const tries = new Array(maxWorkers + 1); + const workers = new Array(maxWorkers); + for (let i = 0; i < maxWorkers; ++i) { + const worker = new Worker(workerPath); + worker.on("error", (err) => { + throw err; + }); + worker.on("messageerror", (err) => { + throw err; + }); + worker.on("exit", (code) => { + if (code > 1 || code < 0) { + throw new Error(`Worker ${worker.threadId} exited with code ${code}`); + } + }); + workers[i] = worker; + } + const tasks = new Array(maxWorkers); + for (let i = 0; i < maxWorkers; ++i) { + const id = i + 1; + const worker = workers[i]; + const [start, end] = chunks[i]; + tasks[i] = new Promise((resolve) => { + worker.once("message", resolve); + worker.postMessage({ end, filePath, id, start }); + }); + } + for await (const res of tasks) { + const id = res.id; + counts[id] = res.counts; + maxes[id] = res.maxes; + mins[id] = res.mins; + sums[id] = res.sums; + tries[id] = res.trie; + } + for (let i = 0; i < maxWorkers; ++i) { + await workers[i].terminate(); + } + for (let i = 2; i <= maxWorkers; ++i) { + mergeLeft(tries, 1, i, mergeStations); + } + const out = createWriteStream("", { + flags: "a", + fd: 1, + highWaterMark: HIGH_WATER_MARK_OUT + }); + const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN); + out.write("{"); + print(tries, buffer, 1, out, ", ", printStation); + out.end("}\n"); + function mergeStations(at, ai, bt, bi) { + counts[at][ai] += counts[bt][bi]; + maxes[at][ai] = Math.max(maxes[at][ai], maxes[bt][bi]); + mins[at][ai] = Math.min(mins[at][ai], mins[bt][bi]); + sums[at][ai] += sums[bt][bi]; + } + function printStation(stream, name, nameLen, vt, vi) { + const avg = Math.round(sums[vt][vi] / counts[vt][vi]); + stream.write(name.toString("utf8", 0, nameLen)); + stream.write("="); + stream.write((mins[vt][vi] / 10).toFixed(1)); + stream.write("/"); + stream.write((avg / 10).toFixed(1)); + stream.write("/"); + stream.write((maxes[vt][vi] / 10).toFixed(1)); + } +} + +async function run({ + end, + filePath, + id, + start +}) { + const counts = new Uint32Array(MAX_STATIONS); + const maxes = new Int16Array(MAX_STATIONS); + const mins = new Int16Array(MAX_STATIONS); + const sums = new Float64Array(MAX_STATIONS); + if (start >= end) { + return { id, trie: createTrie(id, 0), counts, maxes, mins, sums }; + } + let trie = createTrie(id); + let stations = 0; + const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN); + const stream = createReadStream(filePath, { + start, + end: end - 1, + highWaterMark: getHighWaterMark(end - start) + }); + let bufI = 0; + let tempI = 0; + let leaf; + for await (const chunk of stream) { + const N = chunk.length; + for (let i = 0; i < N; ++i) { + if (chunk[i] === CHAR_SEMICOLON) { + tempI = bufI; + } else if (chunk[i] !== CHAR_NEWLINE) { + buffer[bufI++] = chunk[i]; + } else { + const tempV = parseDouble(buffer, tempI, bufI); + bufI = 0; + [trie, leaf] = add(trie, buffer, 0, tempI); + if (trie[leaf + TRIE_NODE_VALUE_ID_IDX] !== TRIE_NULL) { + updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV); + } else { + trie[leaf + TRIE_NODE_VALUE_ID_IDX] = id; + trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations; + newStation(stations++, tempV); + } + } + } + } + function newStation(index, temp) { + counts[index] = 1; + maxes[index] = temp; + mins[index] = temp; + sums[index] = temp; + } + function updateStation(index, temp) { + ++counts[index]; + maxes[index] = maxes[index] >= temp ? maxes[index] : temp; + mins[index] = mins[index] <= temp ? mins[index] : temp; + sums[index] += temp; + } + return { id, trie, counts, maxes, mins, sums }; +} +function parseDouble(b, min, max) { + if (b[min] === CHAR_MINUS) { + return ++min + 4 > max ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11) : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111); + } + return min + 4 > max ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11 : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111; +} + +if (isMainThread) { + const workerPath = fileURLToPath(import.meta.url); + run$1(process.argv[2], workerPath, os.availableParallelism()); +} else { + parentPort.addListener("message", async (req) => { + const res = await run(req); + parentPort.postMessage(res, [ + res.trie.buffer, + res.counts.buffer, + res.maxes.buffer, + res.mins.buffer, + res.sums.buffer + ]); + }); +} +//# sourceMappingURL=index.mjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map new file mode 100644 index 0000000..e0f84aa --- /dev/null +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -0,0 +1 @@ +{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/trie.ts","../src/utils/trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n/**\n * The maximum value of a byte for UTF-8 code points of up to 2 bytes.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_2B_MAX = 224;\n\n/**\n * The number of non-printable control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_PRINT_OFFSET = 32;\n\n/**\n * The number of printable byte values for UTF-8 code points of up to 2 bytes.\n */\nexport const UTF8_2B_PRINT_MAX = UTF8_2B_MAX - UTF8_PRINT_OFFSET;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_2B_PRINT_MAX } from \"./utf8\";\n\n// Trie static properties\n\n/**\n * Represents null / undefined.\n */\nexport const TRIE_NULL = 0;\n\n/**\n * The minimum size a trie.\n */\nexport const MIN_TRIE_SIZE = 524288; // 2 MiB\n\n/**\n * The default growth factor for growing the size of a trie.\n */\nexport const TRIE_GROWTH_FACTOR = 1.618; // ~phi\n\n/**\n * All trie properties are represented by 32 bits (4 bytes).\n */\nexport const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT;\n\n/**\n * The maximum number of children of any trie node.\n */\nexport const TRIE_MAX_CHILDREN = UTF8_2B_PRINT_MAX;\n\n// Trie child pointer properties\n\nexport const TRIE_CHILD_IDX_IDX = 0;\nexport const TRIE_CHILD_IDX_LEN = 1;\n\nexport const TRIE_CHILD_LEN = TRIE_CHILD_IDX_LEN;\n\n// Trie redirect pointer properties\n\nexport const TRIE_RED_ID_IDX = 0;\nexport const TRIE_RED_ID_LEN = 1;\n\nexport const TRIE_RED_VALUE_IDX_IDX = 1;\nexport const TRIE_RED_VALUE_IDX_LEN = 1;\n\nexport const TRIE_RED_LEN = TRIE_RED_ID_LEN + TRIE_RED_VALUE_IDX_LEN;\n\n// Trie node properties\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_LEN = 1;\n\nexport const TRIE_NODE_VALUE_ID_IDX = 1;\nexport const TRIE_NODE_VALUE_ID_LEN = 1;\n\nexport const TRIE_NODE_VALUE_IDX_IDX = 2;\nexport const TRIE_NODE_VALUE_IDX_LEN = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 3;\nexport const TRIE_NODE_CHILDREN_LEN = TRIE_CHILD_LEN * TRIE_MAX_CHILDREN;\n\nexport const TRIE_NODE_LEN =\n TRIE_NODE_ID_LEN +\n TRIE_NODE_VALUE_ID_LEN +\n TRIE_NODE_VALUE_IDX_LEN +\n TRIE_NODE_CHILDREN_LEN;\n\n// Trie properties\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_LEN = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_LEN = TRIE_NODE_LEN;\n\nexport const TRIE_HEADER_LEN = TRIE_SIZE_LEN + TRIE_ROOT_LEN;\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n MIN_TRIE_SIZE,\n TRIE_CHILD_LEN,\n TRIE_CHILD_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_HEADER_LEN,\n TRIE_ID_IDX,\n TRIE_MAX_CHILDREN,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_CHILDREN_LEN,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_LEN,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NODE_VALUE_ID_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_RED_LEN,\n TRIE_RED_VALUE_IDX_IDX,\n TRIE_RED_ID_IDX,\n} from \"../constants/trie\";\nimport { UTF8_PRINT_OFFSET } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX +\n TRIE_CHILD_LEN * (key[min++] - UTF8_PRINT_OFFSET);\n let child = trie[index + TRIE_CHILD_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_LEN > trie.length) {\n trie = grow(trie, child + TRIE_NODE_LEN);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_LEN;\n // Attach and initialize node\n trie[index + TRIE_CHILD_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array {\n const minSize = TRIE_HEADER_LEN;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (at: number, ai: number, bt: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvt = tries[bt][bi + TRIE_NODE_VALUE_ID_IDX];\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX];\n if (bvt !== TRIE_NULL) {\n // If left value is not null\n const avt = tries[at][ai + TRIE_NODE_VALUE_ID_IDX];\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX];\n if (avt !== TRIE_NULL) {\n mergeFn(avt, avi, bvt, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_ID_IDX] = bvt;\n tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_LEN;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_CHILD_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_RED_LEN > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_RED_LEN);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_RED_LEN;\n // Add new redirect\n tries[at][li + TRIE_RED_ID_IDX] = rt;\n tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n id: number,\n value: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, 0, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childKey, childPtr] = stack[top];\n\n // Check if end of children array\n if (childKey >= TRIE_MAX_CHILDREN) {\n --top;\n continue;\n }\n\n // Update stack top\n ++stack[top][1];\n stack[top][2] += TRIE_CHILD_LEN;\n\n // If just reached node\n if (childKey === 0) {\n // Check if the node has a value\n const nodeIndex = childPtr - TRIE_NODE_CHILDREN_IDX;\n const valueId = tries[trieI][nodeIndex + TRIE_NODE_VALUE_ID_IDX];\n if (valueId !== TRIE_NULL) {\n // Print the node's value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX];\n callbackFn(stream, key, top, valueId, valueIndex);\n }\n }\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX];\n if (childI !== TRIE_NULL) {\n // Resolve child if redirect\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX];\n trieI = childTrieI;\n }\n // Add the child to the stack\n key[top] = childKey + UTF8_PRINT_OFFSET;\n stack[++top] = [trieI, 0, childI + TRIE_NODE_CHILDREN_IDX];\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { ENTRY_MAX_LEN, STATION_NAME_MAX_LEN } from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/trie\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const counts: Uint32Array[] = new Array(maxWorkers + 1);\n const maxes: Int16Array[] = new Array(maxWorkers + 1);\n const mins: Int16Array[] = new Array(maxWorkers + 1);\n const sums: Float64Array[] = new Array(maxWorkers + 1);\n const tries: Int32Array[] = new Array(maxWorkers + 1);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i + 1;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({ end, filePath, id, start } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n const id = res.id;\n counts[id] = res.counts;\n maxes[id] = res.maxes;\n mins[id] = res.mins;\n sums[id] = res.sums;\n tries[id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 2; i <= maxWorkers; ++i) {\n mergeLeft(tries, 1, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(\"\", {\n flags: \"a\",\n fd: 1,\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 1, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(at: number, ai: number, bt: number, bi: number): void {\n counts[at][ai] += counts[bt][bi];\n maxes[at][ai] = Math.max(maxes[at][ai], maxes[bt][bi]);\n mins[at][ai] = Math.min(mins[at][ai], mins[bt][bi]);\n sums[at][ai] += sums[bt][bi];\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vt: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vt][vi] / counts[vt][vi]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vt][vi] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vt][vi] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport {\n TRIE_NODE_VALUE_ID_IDX,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NULL,\n} from \"./constants/trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n}: WorkerRequest): Promise {\n const counts = new Uint32Array(MAX_STATIONS);\n const maxes = new Int16Array(MAX_STATIONS);\n const mins = new Int16Array(MAX_STATIONS);\n const sums = new Float64Array(MAX_STATIONS);\n\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0), counts, maxes, mins, sums };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = 0;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_ID_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_ID_IDX] = id;\n trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n counts[index] = 1;\n maxes[index] = temp;\n mins[index] = temp;\n sums[index] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n ++counts[index];\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n sums[index] += temp;\n }\n\n return { id, trie, counts, maxes, mins, sums };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n return ++min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import os from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, os.availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [\n res.trie.buffer,\n res.counts.buffer,\n res.maxes.buffer,\n res.mins.buffer,\n res.sums.buffer,\n ]);\n });\n}\n"],"names":["at","bt","run","runMain","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/eslint.config.js b/src/main/nodejs/havelessbemore/eslint.config.js new file mode 100644 index 0000000..a9a081b --- /dev/null +++ b/src/main/nodejs/havelessbemore/eslint.config.js @@ -0,0 +1,22 @@ +import eslint from "@eslint/js"; +import globals from "globals"; +import prettierConfig from "eslint-config-prettier"; +import tseslint from "typescript-eslint"; + +/** @type {import('@typescript-eslint/utils').TSESLint.FlatConfig.ConfigArray} */ +export default tseslint.config( + { + ignores: ["dist/", "docs/"], + languageOptions: { + globals: { + ...globals.browser, + ...globals.node, + ...globals.worker, + }, + }, + }, + eslint.configs.recommended, + ...tseslint.configs.recommended, + ...tseslint.configs.stylistic, + prettierConfig, +); diff --git a/src/main/nodejs/havelessbemore/package-lock.json b/src/main/nodejs/havelessbemore/package-lock.json new file mode 100644 index 0000000..89be3a8 --- /dev/null +++ b/src/main/nodejs/havelessbemore/package-lock.json @@ -0,0 +1,2871 @@ +{ + "name": "havelessbemore", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "devDependencies": { + "@rollup/plugin-typescript": "^11.1.6", + "@types/node": "^20.10.6", + "esbuild": "^0.21.2", + "eslint": "^8.57.0", + "eslint-config-prettier": "^9.1.0", + "prettier": "^3.2.5", + "rimraf": "^5.0.7", + "rollup": "^4.17.2", + "rollup-plugin-esbuild": "^6.1.1", + "tslib": "^2.6.2", + "typescript": "^5.4.5", + "typescript-eslint": "^7.10.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.3.tgz", + "integrity": "sha512-yTgnwQpFVYfvvo4SvRFB0SwrW8YjOxEoT7wfMT7Ol5v7v5LDNvSGo67aExmxOb87nQNeWPVvaGBNfQ7BXcrZ9w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.3.tgz", + "integrity": "sha512-bviJOLMgurLJtF1/mAoJLxDZDL6oU5/ztMHnJQRejbJrSc9FFu0QoUoFhvi6qSKJEw9y5oGyvr9fuDtzJ30rNQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.3.tgz", + "integrity": "sha512-c+ty9necz3zB1Y+d/N+mC6KVVkGUUOcm4ZmT5i/Fk5arOaY3i6CA3P5wo/7+XzV8cb4GrI/Zjp8NuOQ9Lfsosw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.3.tgz", + "integrity": "sha512-JReHfYCRK3FVX4Ra+y5EBH1b9e16TV2OxrPAvzMsGeES0X2Ndm9ImQRI4Ket757vhc5XBOuGperw63upesclRw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.3.tgz", + "integrity": "sha512-U3fuQ0xNiAkXOmQ6w5dKpEvXQRSpHOnbw7gEfHCRXPeTKW9sBzVck6C5Yneb8LfJm0l6le4NQfkNPnWMSlTFUQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.3.tgz", + "integrity": "sha512-3m1CEB7F07s19wmaMNI2KANLcnaqryJxO1fXHUV5j1rWn+wMxdUYoPyO2TnAbfRZdi7ADRwJClmOwgT13qlP3Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.3.tgz", + "integrity": "sha512-fsNAAl5pU6wmKHq91cHWQT0Fz0vtyE1JauMzKotrwqIKAswwP5cpHUCxZNSTuA/JlqtScq20/5KZ+TxQdovU/g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.3.tgz", + "integrity": "sha512-tci+UJ4zP5EGF4rp8XlZIdq1q1a/1h9XuronfxTMCNBslpCtmk97Q/5qqy1Mu4zIc0yswN/yP/BLX+NTUC1bXA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.3.tgz", + "integrity": "sha512-f6kz2QpSuyHHg01cDawj0vkyMwuIvN62UAguQfnNVzbge2uWLhA7TCXOn83DT0ZvyJmBI943MItgTovUob36SQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.3.tgz", + "integrity": "sha512-vvG6R5g5ieB4eCJBQevyDMb31LMHthLpXTc2IGkFnPWS/GzIFDnaYFp558O+XybTmYrVjxnryru7QRleJvmZ6Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.3.tgz", + "integrity": "sha512-HjCWhH7K96Na+66TacDLJmOI9R8iDWDDiqe17C7znGvvE4sW1ECt9ly0AJ3dJH62jHyVqW9xpxZEU1jKdt+29A==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.3.tgz", + "integrity": "sha512-BGpimEccmHBZRcAhdlRIxMp7x9PyJxUtj7apL2IuoG9VxvU/l/v1z015nFs7Si7tXUwEsvjc1rOJdZCn4QTU+Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.3.tgz", + "integrity": "sha512-5rMOWkp7FQGtAH3QJddP4w3s47iT20hwftqdm7b+loe95o8JU8ro3qZbhgMRy0VuFU0DizymF1pBKkn3YHWtsw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.3.tgz", + "integrity": "sha512-h0zj1ldel89V5sjPLo5H1SyMzp4VrgN1tPkN29TmjvO1/r0MuMRwJxL8QY05SmfsZRs6TF0c/IDH3u7XYYmbAg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.3.tgz", + "integrity": "sha512-dkAKcTsTJ+CRX6bnO17qDJbLoW37npd5gSNtSzjYQr0svghLJYGYB0NF1SNcU1vDcjXLYS5pO4qOW4YbFama4A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.3.tgz", + "integrity": "sha512-vnD1YUkovEdnZWEuMmy2X2JmzsHQqPpZElXx6dxENcIwTu+Cu5ERax6+Ke1QsE814Zf3c6rxCfwQdCTQ7tPuXA==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.3.tgz", + "integrity": "sha512-IOXOIm9WaK7plL2gMhsWJd+l2bfrhfilv0uPTptoRoSb2p09RghhQQp9YY6ZJhk/kqmeRt6siRdMSLLwzuT0KQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.3.tgz", + "integrity": "sha512-uTgCwsvQ5+vCQnqM//EfDSuomo2LhdWhFPS8VL8xKf+PKTCrcT/2kPPoWMTs22aB63MLdGMJiE3f1PHvCDmUOw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.3.tgz", + "integrity": "sha512-vNAkR17Ub2MgEud2Wag/OE4HTSI6zlb291UYzHez/psiKarp0J8PKGDnAhMBcHFoOHMXHfExzmjMojJNbAStrQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.3.tgz", + "integrity": "sha512-W8H9jlGiSBomkgmouaRoTXo49j4w4Kfbl6I1bIdO/vT0+0u4f20ko3ELzV3hPI6XV6JNBVX+8BC+ajHkvffIJA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.3.tgz", + "integrity": "sha512-EjEomwyLSCg8Ag3LDILIqYCZAq/y3diJ04PnqGRgq8/4O3VNlXyMd54j/saShaN4h5o5mivOjAzmU6C3X4v0xw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.3.tgz", + "integrity": "sha512-WGiE/GgbsEwR33++5rzjiYsKyHywE8QSZPF7Rfx9EBfK3Qn3xyR6IjyCr5Uk38Kg8fG4/2phN7sXp4NPWd3fcw==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.3.tgz", + "integrity": "sha512-xRxC0jaJWDLYvcUvjQmHCJSfMrgmUuvsoXgDeU/wTorQ1ngDdUBuFtgY3W1Pc5sprGAvZBtWdJX7RPg/iZZUqA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "dev": true + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@rollup/plugin-typescript": { + "version": "11.1.6", + "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-11.1.6.tgz", + "integrity": "sha512-R92yOmIACgYdJ7dJ97p4K69I8gg6IEHt8M7dUBxN3W6nrO8uUxX5ixl0yU/N3aZTi8WhPuICvOHXQvF6FaykAA==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.1.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.14.0||^3.0.0||^4.0.0", + "tslib": "*", + "typescript": ">=3.7.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + }, + "tslib": { + "optional": true + } + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz", + "integrity": "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.17.2.tgz", + "integrity": "sha512-NM0jFxY8bB8QLkoKxIQeObCaDlJKewVlIEkuyYKm5An1tdVZ966w2+MPQ2l8LBZLjR+SgyV+nRkTIunzOYBMLQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.17.2.tgz", + "integrity": "sha512-yeX/Usk7daNIVwkq2uGoq2BYJKZY1JfyLTaHO/jaiSwi/lsf8fTFoQW/n6IdAsx5tx+iotu2zCJwz8MxI6D/Bw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.17.2.tgz", + "integrity": "sha512-kcMLpE6uCwls023+kknm71ug7MZOrtXo+y5p/tsg6jltpDtgQY1Eq5sGfHcQfb+lfuKwhBmEURDga9N0ol4YPw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.17.2.tgz", + "integrity": "sha512-AtKwD0VEx0zWkL0ZjixEkp5tbNLzX+FCqGG1SvOu993HnSz4qDI6S4kGzubrEJAljpVkhRSlg5bzpV//E6ysTQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.17.2.tgz", + "integrity": "sha512-3reX2fUHqN7sffBNqmEyMQVj/CKhIHZd4y631duy0hZqI8Qoqf6lTtmAKvJFYa6bhU95B1D0WgzHkmTg33In0A==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.17.2.tgz", + "integrity": "sha512-uSqpsp91mheRgw96xtyAGP9FW5ChctTFEoXP0r5FAzj/3ZRv3Uxjtc7taRQSaQM/q85KEKjKsZuiZM3GyUivRg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.17.2.tgz", + "integrity": "sha512-EMMPHkiCRtE8Wdk3Qhtciq6BndLtstqZIroHiiGzB3C5LDJmIZcSzVtLRbwuXuUft1Cnv+9fxuDtDxz3k3EW2A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.17.2.tgz", + "integrity": "sha512-NMPylUUZ1i0z/xJUIx6VUhISZDRT+uTWpBcjdv0/zkp7b/bQDF+NfnfdzuTiB1G6HTodgoFa93hp0O1xl+/UbA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.17.2.tgz", + "integrity": "sha512-T19My13y8uYXPw/L/k0JYaX1fJKFT/PWdXiHr8mTbXWxjVF1t+8Xl31DgBBvEKclw+1b00Chg0hxE2O7bTG7GQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.17.2.tgz", + "integrity": "sha512-BOaNfthf3X3fOWAB+IJ9kxTgPmMqPPH5f5k2DcCsRrBIbWnaJCgX2ll77dV1TdSy9SaXTR5iDXRL8n7AnoP5cg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.17.2.tgz", + "integrity": "sha512-W0UP/x7bnn3xN2eYMql2T/+wpASLE5SjObXILTMPUBDB/Fg/FxC+gX4nvCfPBCbNhz51C+HcqQp2qQ4u25ok6g==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.17.2.tgz", + "integrity": "sha512-Hy7pLwByUOuyaFC6mAr7m+oMC+V7qyifzs/nW2OJfC8H4hbCzOX07Ov0VFk/zP3kBsELWNFi7rJtgbKYsav9QQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.17.2.tgz", + "integrity": "sha512-h1+yTWeYbRdAyJ/jMiVw0l6fOOm/0D1vNLui9iPuqgRGnXA0u21gAqOyB5iHjlM9MMfNOm9RHCQ7zLIzT0x11Q==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.17.2.tgz", + "integrity": "sha512-tmdtXMfKAjy5+IQsVtDiCfqbynAQE/TQRpWdVataHmhMb9DCoJxp9vLcCBjEQWMiUYxO1QprH/HbY9ragCEFLA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.17.2.tgz", + "integrity": "sha512-7II/QCSTAHuE5vdZaQEwJq2ZACkBpQDOmQsE6D6XUbnBHW8IAhm4eTufL6msLJorzrHDFv3CF8oCA/hSIRuZeQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.17.2.tgz", + "integrity": "sha512-TGGO7v7qOq4CYmSBVEYpI1Y5xDuCEnbVC5Vth8mOsW0gDSzxNrVERPc790IGHsrT2dQSimgMr9Ub3Y1Jci5/8w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.12.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz", + "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.10.0.tgz", + "integrity": "sha512-PzCr+a/KAef5ZawX7nbyNwBDtM1HdLIT53aSA2DDlxmxMngZ43O8SIePOeX8H5S+FHXeI6t97mTt/dDdzY4Fyw==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.10.0", + "@typescript-eslint/type-utils": "7.10.0", + "@typescript-eslint/utils": "7.10.0", + "@typescript-eslint/visitor-keys": "7.10.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.10.0.tgz", + "integrity": "sha512-2EjZMA0LUW5V5tGQiaa2Gys+nKdfrn2xiTIBLR4fxmPmVSvgPcKNW+AE/ln9k0A4zDUti0J/GZXMDupQoI+e1w==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "7.10.0", + "@typescript-eslint/types": "7.10.0", + "@typescript-eslint/typescript-estree": "7.10.0", + "@typescript-eslint/visitor-keys": "7.10.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.10.0.tgz", + "integrity": "sha512-7L01/K8W/VGl7noe2mgH0K7BE29Sq6KAbVmxurj8GGaPDZXPr8EEQ2seOeAS+mEV9DnzxBQB6ax6qQQ5C6P4xg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.10.0", + "@typescript-eslint/visitor-keys": "7.10.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.10.0.tgz", + "integrity": "sha512-D7tS4WDkJWrVkuzgm90qYw9RdgBcrWmbbRkrLA4d7Pg3w0ttVGDsvYGV19SH8gPR5L7OtcN5J1hTtyenO9xE9g==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "7.10.0", + "@typescript-eslint/utils": "7.10.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.10.0.tgz", + "integrity": "sha512-7fNj+Ya35aNyhuqrA1E/VayQX9Elwr8NKZ4WueClR3KwJ7Xx9jcCdOrLW04h51de/+gNbyFMs+IDxh5xIwfbNg==", + "dev": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.10.0.tgz", + "integrity": "sha512-LXFnQJjL9XIcxeVfqmNj60YhatpRLt6UhdlFwAkjNc6jSUlK8zQOl1oktAP8PlWFzPQC1jny/8Bai3/HPuvN5g==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.10.0", + "@typescript-eslint/visitor-keys": "7.10.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.10.0.tgz", + "integrity": "sha512-olzif1Fuo8R8m/qKkzJqT7qwy16CzPRWBvERS0uvyc+DHd8AKbO4Jb7kpAvVzMmZm8TrHnI7hvjN4I05zow+tg==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.10.0", + "@typescript-eslint/types": "7.10.0", + "@typescript-eslint/typescript-estree": "7.10.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.10.0.tgz", + "integrity": "sha512-9ntIVgsi6gg6FIq9xjEO4VQJvwOqA3jaBFQJ/6TK5AvEup2+cECI6Fh7QiBxmfMHXU0V0J4RyPeOU1VDNzl9cg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.10.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/es-module-lexer": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.3.tgz", + "integrity": "sha512-i1gCgmR9dCl6Vil6UKPI/trA69s08g/syhiDK9TG0Nf1RJjjFI+AzoWW7sPufzkgYAn861skuCwJa0pIIHYxvg==", + "dev": true + }, + "node_modules/esbuild": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.3.tgz", + "integrity": "sha512-Kgq0/ZsAPzKrbOjCQcjoSmPoWhlcVnGAUo7jvaLHoxW1Drto0KGkR1xBNg2Cp43b9ImvxmPEJZ9xkfcnqPsfBw==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.3", + "@esbuild/android-arm": "0.21.3", + "@esbuild/android-arm64": "0.21.3", + "@esbuild/android-x64": "0.21.3", + "@esbuild/darwin-arm64": "0.21.3", + "@esbuild/darwin-x64": "0.21.3", + "@esbuild/freebsd-arm64": "0.21.3", + "@esbuild/freebsd-x64": "0.21.3", + "@esbuild/linux-arm": "0.21.3", + "@esbuild/linux-arm64": "0.21.3", + "@esbuild/linux-ia32": "0.21.3", + "@esbuild/linux-loong64": "0.21.3", + "@esbuild/linux-mips64el": "0.21.3", + "@esbuild/linux-ppc64": "0.21.3", + "@esbuild/linux-riscv64": "0.21.3", + "@esbuild/linux-s390x": "0.21.3", + "@esbuild/linux-x64": "0.21.3", + "@esbuild/netbsd-x64": "0.21.3", + "@esbuild/openbsd-x64": "0.21.3", + "@esbuild/sunos-x64": "0.21.3", + "@esbuild/win32-arm64": "0.21.3", + "@esbuild/win32-ia32": "0.21.3", + "@esbuild/win32-x64": "0.21.3" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flat-cache/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/flat-cache/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-tsconfig": { + "version": "4.7.5", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.5.tgz", + "integrity": "sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==", + "dev": true, + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob": { + "version": "10.3.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.15.tgz", + "integrity": "sha512-0c6RlJt1TICLyvJYIApxb8GsXoai0KUP7AxKKAtsYXdgJR1mGEUa7DgwShbdk1nly0PYoZj01xd4hzbq3fsjpw==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.6", + "minimatch": "^9.0.1", + "minipass": "^7.0.4", + "path-scurry": "^1.11.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", + "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lru-cache": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", + "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.6.tgz", + "integrity": "sha512-Y4Ypn3oujJYxJcMacVgcs92wofTHxp9FzfDpQON4msDefoC0lb3ETvQLOdLcbhSwU1bz8HrL/1sygfBIHudrkQ==", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minipass": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.1.tgz", + "integrity": "sha512-UZ7eQ+h8ywIRAW1hIEl2AqdwzJucU/Kp59+8kkZeSvafXhZjul247BvIJjEVFVeON6d7lM46XX1HXCduKAS8VA==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.7.tgz", + "integrity": "sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==", + "dev": true, + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.17.2.tgz", + "integrity": "sha512-/9ClTJPByC0U4zNLowV1tMBe8yMEAxewtR3cUNX5BoEpGH3dQEWpJLr6CLp0fPdYRF/fzVOgvDb1zXuakwF5kQ==", + "dev": true, + "dependencies": { + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.17.2", + "@rollup/rollup-android-arm64": "4.17.2", + "@rollup/rollup-darwin-arm64": "4.17.2", + "@rollup/rollup-darwin-x64": "4.17.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.17.2", + "@rollup/rollup-linux-arm-musleabihf": "4.17.2", + "@rollup/rollup-linux-arm64-gnu": "4.17.2", + "@rollup/rollup-linux-arm64-musl": "4.17.2", + "@rollup/rollup-linux-powerpc64le-gnu": "4.17.2", + "@rollup/rollup-linux-riscv64-gnu": "4.17.2", + "@rollup/rollup-linux-s390x-gnu": "4.17.2", + "@rollup/rollup-linux-x64-gnu": "4.17.2", + "@rollup/rollup-linux-x64-musl": "4.17.2", + "@rollup/rollup-win32-arm64-msvc": "4.17.2", + "@rollup/rollup-win32-ia32-msvc": "4.17.2", + "@rollup/rollup-win32-x64-msvc": "4.17.2", + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup-plugin-esbuild": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/rollup-plugin-esbuild/-/rollup-plugin-esbuild-6.1.1.tgz", + "integrity": "sha512-CehMY9FAqJD5OUaE/Mi1r5z0kNeYxItmRO2zG4Qnv2qWKF09J2lTy5GUzjJR354ZPrLkCj4fiBN41lo8PzBUhw==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.5", + "debug": "^4.3.4", + "es-module-lexer": "^1.3.1", + "get-tsconfig": "^4.7.2" + }, + "engines": { + "node": ">=14.18.0" + }, + "peerDependencies": { + "esbuild": ">=0.18.0", + "rollup": "^1.20.0 || ^2.0.0 || ^3.0.0 || ^4.0.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/semver": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "7.10.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.10.0.tgz", + "integrity": "sha512-thO8nyqptXdfWHQrMJJiJyftpW8aLmwRNs11xA8pSrXneoclFPstQZqXvDWuH1WNL4CHffqHvYUeCHTit6yfhQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/eslint-plugin": "7.10.0", + "@typescript-eslint/parser": "7.10.0", + "@typescript-eslint/utils": "7.10.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/src/main/nodejs/havelessbemore/package.json b/src/main/nodejs/havelessbemore/package.json new file mode 100644 index 0000000..bbcd382 --- /dev/null +++ b/src/main/nodejs/havelessbemore/package.json @@ -0,0 +1,36 @@ +{ + "sideEffects": false, + "engines": { + "node": ">= 18" + }, + "type": "module", + "main": "./dist/index.cjs", + "module": "./dist/index.mjs", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "import": "./dist/index.mjs", + "require": "./dist/index.cjs", + "types": "./dist/index.d.ts" + } + }, + "scripts": { + "build": "rimraf dist && tsc && rollup -c --configPlugin typescript", + "format": "prettier . --write", + "lint": "eslint" + }, + "devDependencies": { + "@rollup/plugin-typescript": "^11.1.6", + "@types/node": "^20.10.6", + "esbuild": "^0.21.2", + "eslint": "^8.57.0", + "eslint-config-prettier": "^9.1.0", + "prettier": "^3.2.5", + "rimraf": "^5.0.7", + "rollup": "^4.17.2", + "rollup-plugin-esbuild": "^6.1.1", + "tslib": "^2.6.2", + "typescript": "^5.4.5", + "typescript-eslint": "^7.10.0" + } +} diff --git a/src/main/nodejs/havelessbemore/rollup.config.ts b/src/main/nodejs/havelessbemore/rollup.config.ts new file mode 100644 index 0000000..31a6cc5 --- /dev/null +++ b/src/main/nodejs/havelessbemore/rollup.config.ts @@ -0,0 +1,32 @@ +import { RollupOptions } from "rollup"; +import esbuild from "rollup-plugin-esbuild"; + +import pkg from "./package.json" with { type: "json" }; + +function bundle(config: RollupOptions): RollupOptions { + return { + ...config, + input: "src/index.ts", + external: (id) => !/^[./]/.test(id), + }; +} + +export default [ + bundle({ + plugins: [esbuild({ target: "ES2022" })], + output: [ + { + file: pkg.main, + format: "cjs", + sourcemap: true, + exports: "named", + }, + { + file: pkg.module, + format: "es", + sourcemap: true, + exports: "named", + }, + ], + }), +]; diff --git a/src/main/nodejs/havelessbemore/src/constants/constraints.ts b/src/main/nodejs/havelessbemore/src/constants/constraints.ts new file mode 100644 index 0000000..b544d3f --- /dev/null +++ b/src/main/nodejs/havelessbemore/src/constants/constraints.ts @@ -0,0 +1,25 @@ +/** + * The maximum number of entries in the file (i.e. 1 billion). + */ +export const MAX_ENTRIES = 1e9; + +/** + * The maximum number of unique stations (i.e. 10 thousand). + */ +export const MAX_STATIONS = 1e4; + +/** + * The maximum length in bytes of a station name (i.e. 100 bytes). + */ +export const STATION_NAME_MAX_LEN = 100; + +/** + * The maximum length in bytes of an entry. + * + * Example: `Abha;71.3` + * - Station name: 1-100 bytes + * - Semicolon: 1 byte + * - Temperature: 3-5 bytes + * - Newline: 1 byte + */ +export const ENTRY_MAX_LEN = 107; diff --git a/src/main/nodejs/havelessbemore/src/constants/stream.ts b/src/main/nodejs/havelessbemore/src/constants/stream.ts new file mode 100644 index 0000000..fee19cd --- /dev/null +++ b/src/main/nodejs/havelessbemore/src/constants/stream.ts @@ -0,0 +1,39 @@ +import { CHAR_ZERO } from "./utf8"; + +/** + * The minimum value in bytes for `highWaterMark`. + */ +export const HIGH_WATER_MARK_MIN = 16384; // 16KiB + +/** + * The maximum value in bytes for `highWaterMark`. + */ +export const HIGH_WATER_MARK_MAX = 1048576; // 1MiB + +/** + * The `highWaterMark` for write streams. + */ +export const HIGH_WATER_MARK_OUT = 1048576; // 1MiB + +/** + * The ratio of the file size to use for calculating + * the `highWaterMark` of a stream. + */ +export const HIGH_WATER_MARK_RATIO = 0.000152; + +/** + * The minimum size in bytes of a file chunk. + */ +export const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN; + +// PARSE DOUBLE + +/** + * Used to parse doubles from -9.9 to 9.9. + */ +export const CHAR_ZERO_11 = 11 * CHAR_ZERO; + +/** + * Used to parse doubles from -99.9 to 99.9. + */ +export const CHAR_ZERO_111 = 111 * CHAR_ZERO; diff --git a/src/main/nodejs/havelessbemore/src/constants/trie.ts b/src/main/nodejs/havelessbemore/src/constants/trie.ts new file mode 100644 index 0000000..0e3c436 --- /dev/null +++ b/src/main/nodejs/havelessbemore/src/constants/trie.ts @@ -0,0 +1,76 @@ +import { UTF8_2B_PRINT_MAX } from "./utf8"; + +// Trie static properties + +/** + * Represents null / undefined. + */ +export const TRIE_NULL = 0; + +/** + * The minimum size a trie. + */ +export const MIN_TRIE_SIZE = 524288; // 2 MiB + +/** + * The default growth factor for growing the size of a trie. + */ +export const TRIE_GROWTH_FACTOR = 1.618; // ~phi + +/** + * All trie properties are represented by 32 bits (4 bytes). + */ +export const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT; + +/** + * The maximum number of children of any trie node. + */ +export const TRIE_MAX_CHILDREN = UTF8_2B_PRINT_MAX; + +// Trie child pointer properties + +export const TRIE_CHILD_IDX_IDX = 0; +export const TRIE_CHILD_IDX_LEN = 1; + +export const TRIE_CHILD_LEN = TRIE_CHILD_IDX_LEN; + +// Trie redirect pointer properties + +export const TRIE_RED_ID_IDX = 0; +export const TRIE_RED_ID_LEN = 1; + +export const TRIE_RED_VALUE_IDX_IDX = 1; +export const TRIE_RED_VALUE_IDX_LEN = 1; + +export const TRIE_RED_LEN = TRIE_RED_ID_LEN + TRIE_RED_VALUE_IDX_LEN; + +// Trie node properties + +export const TRIE_NODE_ID_IDX = 0; +export const TRIE_NODE_ID_LEN = 1; + +export const TRIE_NODE_VALUE_ID_IDX = 1; +export const TRIE_NODE_VALUE_ID_LEN = 1; + +export const TRIE_NODE_VALUE_IDX_IDX = 2; +export const TRIE_NODE_VALUE_IDX_LEN = 1; + +export const TRIE_NODE_CHILDREN_IDX = 3; +export const TRIE_NODE_CHILDREN_LEN = TRIE_CHILD_LEN * TRIE_MAX_CHILDREN; + +export const TRIE_NODE_LEN = + TRIE_NODE_ID_LEN + + TRIE_NODE_VALUE_ID_LEN + + TRIE_NODE_VALUE_IDX_LEN + + TRIE_NODE_CHILDREN_LEN; + +// Trie properties + +export const TRIE_SIZE_IDX = 0; +export const TRIE_SIZE_LEN = 1; + +export const TRIE_ROOT_IDX = 1; +export const TRIE_ROOT_LEN = TRIE_NODE_LEN; + +export const TRIE_HEADER_LEN = TRIE_SIZE_LEN + TRIE_ROOT_LEN; +export const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX; diff --git a/src/main/nodejs/havelessbemore/src/constants/utf8.ts b/src/main/nodejs/havelessbemore/src/constants/utf8.ts new file mode 100644 index 0000000..6e70dee --- /dev/null +++ b/src/main/nodejs/havelessbemore/src/constants/utf8.ts @@ -0,0 +1,43 @@ +/** + * The char code for a minus sign: - + */ +export const CHAR_MINUS = 45; // "-".charCodeAt(0); + +/** + * The char code for a newline: \n + */ +export const CHAR_NEWLINE = 10; // "\n".charCodeAt(0); + +/** + * The char code for a period: . + */ +export const CHAR_PERIOD = 46; // ".".charCodeAt(0); + +/** + * The char code for a semicolon: ; + */ +export const CHAR_SEMICOLON = 59; // ";".charCodeAt(0); + +/** + * The char code for a zero: 0 + */ +export const CHAR_ZERO = 48; // "0".charCodeAt(0); + +/** + * The maximum value of a byte for UTF-8 code points of up to 2 bytes. + * + * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding} + */ +export const UTF8_2B_MAX = 224; + +/** + * The number of non-printable control code points from U+0000 to U+001F. + * + * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset} + */ +export const UTF8_PRINT_OFFSET = 32; + +/** + * The number of printable byte values for UTF-8 code points of up to 2 bytes. + */ +export const UTF8_2B_PRINT_MAX = UTF8_2B_MAX - UTF8_PRINT_OFFSET; diff --git a/src/main/nodejs/havelessbemore/src/constants/workers.ts b/src/main/nodejs/havelessbemore/src/constants/workers.ts new file mode 100644 index 0000000..248e0f8 --- /dev/null +++ b/src/main/nodejs/havelessbemore/src/constants/workers.ts @@ -0,0 +1,9 @@ +/** + * The minimum number of web workers (inclusive). + */ +export const MIN_WORKERS = 1; + +/** + * The maximum number of web workers (inclusive). + */ +export const MAX_WORKERS = 512; diff --git a/src/main/nodejs/havelessbemore/src/index.ts b/src/main/nodejs/havelessbemore/src/index.ts new file mode 100644 index 0000000..e404108 --- /dev/null +++ b/src/main/nodejs/havelessbemore/src/index.ts @@ -0,0 +1,24 @@ +import os from "node:os"; +import { fileURLToPath } from "node:url"; +import { isMainThread, parentPort } from "node:worker_threads"; + +import type { WorkerRequest } from "./types/workerRequest"; + +import { run as runMain } from "./main"; +import { run as runWorker } from "./worker"; + +if (isMainThread) { + const workerPath = fileURLToPath(import.meta.url); + runMain(process.argv[2], workerPath, os.availableParallelism()); +} else { + parentPort!.addListener("message", async (req: WorkerRequest) => { + const res = await runWorker(req); + parentPort!.postMessage(res, [ + res.trie.buffer, + res.counts.buffer, + res.maxes.buffer, + res.mins.buffer, + res.sums.buffer, + ]); + }); +} diff --git a/src/main/nodejs/havelessbemore/src/main.ts b/src/main/nodejs/havelessbemore/src/main.ts new file mode 100644 index 0000000..22296b3 --- /dev/null +++ b/src/main/nodejs/havelessbemore/src/main.ts @@ -0,0 +1,123 @@ +import { WriteStream, createWriteStream } from "node:fs"; +import { Worker } from "node:worker_threads"; + +import type { WorkerRequest } from "./types/workerRequest"; +import type { WorkerResponse } from "./types/workerResponse"; + +import { ENTRY_MAX_LEN, STATION_NAME_MAX_LEN } from "./constants/constraints"; +import { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from "./constants/stream"; +import { MAX_WORKERS, MIN_WORKERS } from "./constants/workers"; +import { clamp, getFileChunks } from "./utils/stream"; +import { mergeLeft, print } from "./utils/trie"; + +export async function run( + filePath: string, + workerPath: string, + maxWorkers: number, +): Promise { + // Sanitize number of workers + maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS); + + // Split the file into chunks. Creates 1 or fewer chunks per worker + const chunks = await getFileChunks( + filePath, + maxWorkers, + ENTRY_MAX_LEN, + CHUNK_SIZE_MIN, + ); + + // Adjust the number of workers to the number of chunks + maxWorkers = chunks.length; + + // Initialize data + const counts: Uint32Array[] = new Array(maxWorkers + 1); + const maxes: Int16Array[] = new Array(maxWorkers + 1); + const mins: Int16Array[] = new Array(maxWorkers + 1); + const sums: Float64Array[] = new Array(maxWorkers + 1); + const tries: Int32Array[] = new Array(maxWorkers + 1); + + // Create workers + const workers = new Array(maxWorkers); + for (let i = 0; i < maxWorkers; ++i) { + const worker = new Worker(workerPath); + worker.on("error", (err) => { + throw err; + }); + worker.on("messageerror", (err) => { + throw err; + }); + worker.on("exit", (code) => { + if (code > 1 || code < 0) { + throw new Error(`Worker ${worker.threadId} exited with code ${code}`); + } + }); + workers[i] = worker; + } + + // Process each chunk + const tasks = new Array>(maxWorkers); + for (let i = 0; i < maxWorkers; ++i) { + const id = i + 1; + const worker = workers[i]; + const [start, end] = chunks[i]; + tasks[i] = new Promise((resolve) => { + worker.once("message", resolve); + worker.postMessage({ end, filePath, id, start } as WorkerRequest); + }); + } + + // Wait for completion + for await (const res of tasks) { + const id = res.id; + counts[id] = res.counts; + maxes[id] = res.maxes; + mins[id] = res.mins; + sums[id] = res.sums; + tries[id] = res.trie; + } + + // Terminate workers + for (let i = 0; i < maxWorkers; ++i) { + await workers[i].terminate(); + } + + // Merge tries + for (let i = 2; i <= maxWorkers; ++i) { + mergeLeft(tries, 1, i, mergeStations); + } + + // Print results + const out = createWriteStream("", { + flags: "a", + fd: 1, + highWaterMark: HIGH_WATER_MARK_OUT, + }); + const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN); + out.write("{"); + print(tries, buffer, 1, out, ", ", printStation); + out.end("}\n"); + + function mergeStations(at: number, ai: number, bt: number, bi: number): void { + counts[at][ai] += counts[bt][bi]; + maxes[at][ai] = Math.max(maxes[at][ai], maxes[bt][bi]); + mins[at][ai] = Math.min(mins[at][ai], mins[bt][bi]); + sums[at][ai] += sums[bt][bi]; + } + + function printStation( + stream: WriteStream, + name: Buffer, + nameLen: number, + vt: number, + vi: number, + ): void { + const avg = Math.round(sums[vt][vi] / counts[vt][vi]); + stream.write(name.toString("utf8", 0, nameLen)); + stream.write("="); + stream.write((mins[vt][vi] / 10).toFixed(1)); + stream.write("/"); + stream.write((avg / 10).toFixed(1)); + stream.write("/"); + stream.write((maxes[vt][vi] / 10).toFixed(1)); + } +} diff --git a/src/main/nodejs/havelessbemore/src/types/workerRequest.ts b/src/main/nodejs/havelessbemore/src/types/workerRequest.ts new file mode 100644 index 0000000..72202f9 --- /dev/null +++ b/src/main/nodejs/havelessbemore/src/types/workerRequest.ts @@ -0,0 +1,6 @@ +export interface WorkerRequest { + end: number; + filePath: string; + id: number; + start: number; +} diff --git a/src/main/nodejs/havelessbemore/src/types/workerResponse.ts b/src/main/nodejs/havelessbemore/src/types/workerResponse.ts new file mode 100644 index 0000000..155ec56 --- /dev/null +++ b/src/main/nodejs/havelessbemore/src/types/workerResponse.ts @@ -0,0 +1,8 @@ +export interface WorkerResponse { + counts: Uint32Array; + id: number; + maxes: Int16Array; + mins: Int16Array; + sums: Float64Array; + trie: Int32Array; +} diff --git a/src/main/nodejs/havelessbemore/src/utils/stream.ts b/src/main/nodejs/havelessbemore/src/utils/stream.ts new file mode 100644 index 0000000..31f846f --- /dev/null +++ b/src/main/nodejs/havelessbemore/src/utils/stream.ts @@ -0,0 +1,102 @@ +import { open } from "fs/promises"; + +import { CHAR_NEWLINE } from "../constants/utf8"; +import { + HIGH_WATER_MARK_MAX, + HIGH_WATER_MARK_MIN, + HIGH_WATER_MARK_RATIO, +} from "../constants/stream"; + +/** + * Clamp a value within a given range. + * + * @param value - The value to clamp. + * @param min - The range min (inclusive). + * @param max - The range max (inclusive). + * + * @returns The clamped value. + */ +export function clamp(value: number, min: number, max: number): number { + return value > min ? (value <= max ? value : max) : min; +} + +/** + * Splits a file into `target` chunks or less. + * + * - Each chunk is aligned to a file line; + * i.e. file start, newline ('\n') or file end. + * - A chunk's size will be greater than or equal to `fileSize / target`. + * - `target` chunks or less will be generated. + * + * @param filePath - The local path to the file to be chunked. + * @param target - The target number of chunks to split the file into. + * @param maxLineLength - The maximum length of a line in the file. + * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`. + * + * @returns A promise that resolves to an array of index pairs, where each + * pair represents a chunk's start (inclusive) and end (exclusive) indices. + * + * @throws Will throw an error if the file cannot be opened or read. + */ +export async function getFileChunks( + filePath: string, + target: number, + maxLineLength: number, + minSize = 0, +): Promise<[number, number][]> { + // Open the given file + const file = await open(filePath); + try { + // Get the file's size + const size = (await file.stat()).size; + // Calculate each chunk's target size + const chunkSize = Math.max(minSize, Math.floor(size / target)); + // Initialize constants + const buffer = Buffer.allocUnsafe(maxLineLength); + const chunks: [number, number][] = []; + // Traverse the file, visiting each chunk's end index (exclusive) + let start = 0; + for (let end = chunkSize; end < size; end += chunkSize) { + // Read a line at the intended end index + const res = await file.read(buffer, 0, maxLineLength, end); + // Find the nearest newline ('\n') character + const newline = buffer.indexOf(CHAR_NEWLINE); + // If found + if (newline >= 0 && newline < res.bytesRead) { + // Align end with the newline + end += newline + 1; + // Add the chunk + chunks.push([start, end]); + // Update the start index for the next chunk + start = end; + } + } + // Add the last chunk, if necessary + if (start < size) { + chunks.push([start, size]); + } + // Return chunks + return chunks; + } finally { + // Always close the file before returning + await file.close(); + } +} + +/** + * Calculates an optimal highWaterMark value based on the given size. + * + * @param size - The size based on which the highWaterMark will be calculated. + * + * @returns The calculated highWaterMark value. + */ +export function getHighWaterMark(size: number): number { + // Get size percentage + size *= HIGH_WATER_MARK_RATIO; + // Get nearest power + size = Math.round(Math.log2(size)); + // Calculate high water mark + size = 2 ** size; + // Clamp value + return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX); +} diff --git a/src/main/nodejs/havelessbemore/src/utils/trie.ts b/src/main/nodejs/havelessbemore/src/utils/trie.ts new file mode 100644 index 0000000..b90d260 --- /dev/null +++ b/src/main/nodejs/havelessbemore/src/utils/trie.ts @@ -0,0 +1,218 @@ +import { WriteStream } from "node:fs"; + +import { + MIN_TRIE_SIZE, + TRIE_CHILD_LEN, + TRIE_CHILD_IDX_IDX, + TRIE_GROWTH_FACTOR, + TRIE_HEADER_LEN, + TRIE_ID_IDX, + TRIE_MAX_CHILDREN, + TRIE_NODE_CHILDREN_IDX, + TRIE_NODE_CHILDREN_LEN, + TRIE_NODE_ID_IDX, + TRIE_NODE_LEN, + TRIE_NODE_VALUE_IDX_IDX, + TRIE_NODE_VALUE_ID_IDX, + TRIE_NULL, + TRIE_ROOT_IDX, + TRIE_SIZE_IDX, + TRIE_RED_LEN, + TRIE_RED_VALUE_IDX_IDX, + TRIE_RED_ID_IDX, +} from "../constants/trie"; +import { UTF8_PRINT_OFFSET } from "../constants/utf8"; + +export function add( + trie: Int32Array, + key: ArrayLike, + min: number, + max: number, +): [Int32Array, number] { + let index = TRIE_ROOT_IDX; + while (min < max) { + index += + TRIE_NODE_CHILDREN_IDX + + TRIE_CHILD_LEN * (key[min++] - UTF8_PRINT_OFFSET); + let child = trie[index + TRIE_CHILD_IDX_IDX]; + if (child === TRIE_NULL) { + // Allocate new node + child = trie[TRIE_SIZE_IDX]; + if (child + TRIE_NODE_LEN > trie.length) { + trie = grow(trie, child + TRIE_NODE_LEN); + } + trie[TRIE_SIZE_IDX] += TRIE_NODE_LEN; + // Attach and initialize node + trie[index + TRIE_CHILD_IDX_IDX] = child; + trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX]; + } + index = child; + } + + return [trie, index]; +} + +export function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array { + const minSize = TRIE_HEADER_LEN; + const trie = new Int32Array(Math.max(minSize, size)); + trie[TRIE_SIZE_IDX] = minSize; + trie[TRIE_ID_IDX] = id; + return trie; +} + +export function grow(trie: Int32Array, minSize = 0): Int32Array { + const length = trie[TRIE_SIZE_IDX]; + minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR)); + const next = new Int32Array(minSize); + for (let i = 0; i < length; ++i) { + next[i] = trie[i]; + } + return next; +} + +export function mergeLeft( + tries: Int32Array[], + at: number, + bt: number, + mergeFn: (at: number, ai: number, bt: number, bi: number) => void, +): void { + const queue: [number, number, number, number][] = [ + [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX], + ]; + + do { + const Q = queue.length; + for (let q = 0; q < Q; ++q) { + let [at, ai, bt, bi] = queue[q]; + + // If right value is not null + const bvt = tries[bt][bi + TRIE_NODE_VALUE_ID_IDX]; + const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX]; + if (bvt !== TRIE_NULL) { + // If left value is not null + const avt = tries[at][ai + TRIE_NODE_VALUE_ID_IDX]; + const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX]; + if (avt !== TRIE_NULL) { + mergeFn(avt, avi, bvt, bvi); + } else { + tries[at][ai + TRIE_NODE_VALUE_ID_IDX] = bvt; + tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi; + } + } + + // Adjust to children property + ai += TRIE_NODE_CHILDREN_IDX; + bi += TRIE_NODE_CHILDREN_IDX; + + // Traverse right children + const bn = bi + TRIE_NODE_CHILDREN_LEN; + while (bi < bn) { + // If right child is null + let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX]; + if (ri === TRIE_NULL) { + // Move to next children + ai += TRIE_CHILD_LEN; + bi += TRIE_CHILD_LEN; + continue; + } + + // Resolve right child if redirect + const rt = tries[bt][ri + TRIE_NODE_ID_IDX]; + if (bt !== rt) { + ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX]; + } + + // If left child is null + let li = tries[at][ai + TRIE_CHILD_IDX_IDX]; + if (li === TRIE_NULL) { + // Allocate new redirect in left trie + li = tries[at][TRIE_SIZE_IDX]; + if (li + TRIE_RED_LEN > tries[at].length) { + tries[at] = grow(tries[at], li + TRIE_RED_LEN); + } + tries[at][TRIE_SIZE_IDX] += TRIE_RED_LEN; + // Add new redirect + tries[at][li + TRIE_RED_ID_IDX] = rt; + tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri; + } else { + // Resolve left child if redirect + const lt = tries[at][li + TRIE_NODE_ID_IDX]; + if (at !== lt) { + ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX]; + } + // Merge children + queue.push([lt, li, rt, ri]); + } + + // Move to next children + ai += TRIE_CHILD_LEN; + bi += TRIE_CHILD_LEN; + } + } + queue.splice(0, Q); + } while (queue.length > 0); +} + +export function print( + tries: Int32Array[], + key: Buffer, + trieIndex: number, + stream: WriteStream, + separator = "", + callbackFn: ( + stream: WriteStream, + key: Buffer, + keyLen: number, + id: number, + value: number, + ) => void, +): void { + const stack: [number, number, number][] = new Array(key.length + 1); + stack[0] = [trieIndex, 0, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX]; + + let top = 0; + let tail = false; + do { + let [trieI, childKey, childPtr] = stack[top]; + + // Check if end of children array + if (childKey >= TRIE_MAX_CHILDREN) { + --top; + continue; + } + + // Update stack top + ++stack[top][1]; + stack[top][2] += TRIE_CHILD_LEN; + + // If just reached node + if (childKey === 0) { + // Check if the node has a value + const nodeIndex = childPtr - TRIE_NODE_CHILDREN_IDX; + const valueId = tries[trieI][nodeIndex + TRIE_NODE_VALUE_ID_IDX]; + if (valueId !== TRIE_NULL) { + // Print the node's value + if (tail) { + stream.write(separator); + } + tail = true; + const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX]; + callbackFn(stream, key, top, valueId, valueIndex); + } + } + + // Check if child exists + let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX]; + if (childI !== TRIE_NULL) { + // Resolve child if redirect + const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX]; + if (trieI !== childTrieI) { + childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX]; + trieI = childTrieI; + } + // Add the child to the stack + key[top] = childKey + UTF8_PRINT_OFFSET; + stack[++top] = [trieI, 0, childI + TRIE_NODE_CHILDREN_IDX]; + } + } while (top >= 0); +} diff --git a/src/main/nodejs/havelessbemore/src/worker.ts b/src/main/nodejs/havelessbemore/src/worker.ts new file mode 100644 index 0000000..ff73c4d --- /dev/null +++ b/src/main/nodejs/havelessbemore/src/worker.ts @@ -0,0 +1,107 @@ +import { createReadStream } from "node:fs"; + +import type { WorkerRequest } from "./types/workerRequest"; +import type { WorkerResponse } from "./types/workerResponse"; + +import { CHAR_SEMICOLON } from "./constants/utf8"; +import { CHAR_NEWLINE } from "./constants/utf8"; +import { CHAR_MINUS } from "./constants/utf8"; +import { ENTRY_MAX_LEN, MAX_STATIONS } from "./constants/constraints"; +import { CHAR_ZERO_11, CHAR_ZERO_111 } from "./constants/stream"; +import { + TRIE_NODE_VALUE_ID_IDX, + TRIE_NODE_VALUE_IDX_IDX, + TRIE_NULL, +} from "./constants/trie"; +import { getHighWaterMark } from "./utils/stream"; +import { add, createTrie } from "./utils/trie"; + +export async function run({ + end, + filePath, + id, + start, +}: WorkerRequest): Promise { + const counts = new Uint32Array(MAX_STATIONS); + const maxes = new Int16Array(MAX_STATIONS); + const mins = new Int16Array(MAX_STATIONS); + const sums = new Float64Array(MAX_STATIONS); + + // Check chunk size + if (start >= end) { + return { id, trie: createTrie(id, 0), counts, maxes, mins, sums }; + } + + // Initialize constants + let trie = createTrie(id); + let stations = 0; + const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN); + + // Create the chunk stream + const stream = createReadStream(filePath, { + start, + end: end - 1, + highWaterMark: getHighWaterMark(end - start), + }); + + // For each chunk + let bufI = 0; + let tempI = 0; + let leaf: number; + for await (const chunk of stream) { + // For each byte + const N = chunk.length; + for (let i = 0; i < N; ++i) { + if (chunk[i] === CHAR_SEMICOLON) { + // If semicolon + tempI = bufI; + } else if (chunk[i] !== CHAR_NEWLINE) { + // If not newline + buffer[bufI++] = chunk[i]; + } else { + // Get temperature + const tempV = parseDouble(buffer, tempI, bufI); + bufI = 0; + // Add the station's name to the trie and get leaf index + [trie, leaf] = add(trie, buffer, 0, tempI); + // If the station existed + if (trie[leaf + TRIE_NODE_VALUE_ID_IDX] !== TRIE_NULL) { + // Update the station's value + updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV); + } else { + // Add the new station's value + trie[leaf + TRIE_NODE_VALUE_ID_IDX] = id; + trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations; + newStation(stations++, tempV); + } + } + } + } + + function newStation(index: number, temp: number): void { + counts[index] = 1; + maxes[index] = temp; + mins[index] = temp; + sums[index] = temp; + } + + function updateStation(index: number, temp: number): void { + ++counts[index]; + maxes[index] = maxes[index] >= temp ? maxes[index] : temp; + mins[index] = mins[index] <= temp ? mins[index] : temp; + sums[index] += temp; + } + + return { id, trie, counts, maxes, mins, sums }; +} + +export function parseDouble(b: Buffer, min: number, max: number): number { + if (b[min] === CHAR_MINUS) { + return ++min + 4 > max + ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11) + : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111); + } + return min + 4 > max + ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11 + : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111; +} diff --git a/src/main/nodejs/havelessbemore/tsconfig.json b/src/main/nodejs/havelessbemore/tsconfig.json new file mode 100644 index 0000000..2956e64 --- /dev/null +++ b/src/main/nodejs/havelessbemore/tsconfig.json @@ -0,0 +1,115 @@ +{ + "$schema": "http://json.schemastore.org/tsconfig", + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true /* Save .tsbuildinfo files to allow for incremental compilation of projects. */, + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "ES2022" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + "lib": [ + "ESNext" + ] /* Specify a set of bundled library declaration files that describe the target runtime environment. */, + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + "useDefineForClassFields": true /* Emit ECMAScript-standard-compliant class fields. */, + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "ESNext" /* Specify what module code is generated. */, + "rootDir": "." /* Specify the root folder within your source files. */, + "moduleResolution": "Bundler" /* Specify how TypeScript looks up a file from a given module specifier. */, + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + "types": [ + "node" + ] /* Specify type package names to be included without being referenced in a source file. */, + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ + // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ + // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true /* Generate .d.ts files from TypeScript and JavaScript files in your project. */, + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true /* Create source map files for emitted JavaScript files. */, + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + "outDir": "./dist" /* Specify an output folder for all emitted files. */, + // "removeComments": true, /* Disable emitting comments. */ + "noEmit": true /* Disable emitting files from a compilation. */, + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + "stripInternal": true /* Disable emitting declarations that have '@internal' in their JSDoc comments. */, + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, + + /* Type Checking */ + "strict": true /* Enable all strict type-checking options. */, + "noImplicitAny": true /* Enable error reporting for expressions and declarations with an implied 'any' type. */, + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + "strictFunctionTypes": true /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */, + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + "noUnusedLocals": true /* Enable error reporting when local variables aren't read. */, + "noUnusedParameters": true /* Raise an error when a function parameter isn't read. */, + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + "noImplicitReturns": true /* Enable error reporting for codepaths that do not explicitly return in a function. */, + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + }, + "include": ["src", "./*.config.ts"] +} From 92f19b578d97d00f1450192a9ef7aa17494bf2d7 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Tue, 21 May 2024 18:10:57 -0400 Subject: [PATCH 02/69] Remove unused CHANGELOG.md --- src/main/nodejs/havelessbemore/CHANGELOG.md | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 src/main/nodejs/havelessbemore/CHANGELOG.md diff --git a/src/main/nodejs/havelessbemore/CHANGELOG.md b/src/main/nodejs/havelessbemore/CHANGELOG.md deleted file mode 100644 index 5a8f14b..0000000 --- a/src/main/nodejs/havelessbemore/CHANGELOG.md +++ /dev/null @@ -1,12 +0,0 @@ -# Change Log - -## v0.0.1 (2024-05-15) - -- Make a copy of baseline -- Translate baseline into TypeScript - -### Performance - -| real | user | sys | -| --------- | --------- | -------- | -| 5m44.952s | 5m41.587s | 0m4.377s | From 7535b1ab4ae3f40df9baf07985f68ad0c609513c Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Wed, 22 May 2024 09:02:10 -0400 Subject: [PATCH 03/69] Add benchmark and README.md --- src/main/nodejs/havelessbemore/README.md | 55 +++ .../nodejs/havelessbemore/benchmarks/bench.ts | 58 +++ src/main/nodejs/havelessbemore/dist/index.cjs | 8 +- .../nodejs/havelessbemore/dist/index.cjs.map | 2 +- src/main/nodejs/havelessbemore/dist/index.mjs | 8 +- .../nodejs/havelessbemore/dist/index.mjs.map | 2 +- .../nodejs/havelessbemore/package-lock.json | 433 ++++++++++++++++++ src/main/nodejs/havelessbemore/package.json | 3 + src/main/nodejs/havelessbemore/src/index.ts | 4 +- src/main/nodejs/havelessbemore/src/main.ts | 5 +- src/main/nodejs/havelessbemore/tsconfig.json | 2 +- 11 files changed, 565 insertions(+), 15 deletions(-) create mode 100644 src/main/nodejs/havelessbemore/README.md create mode 100644 src/main/nodejs/havelessbemore/benchmarks/bench.ts diff --git a/src/main/nodejs/havelessbemore/README.md b/src/main/nodejs/havelessbemore/README.md new file mode 100644 index 0000000..d0f4467 --- /dev/null +++ b/src/main/nodejs/havelessbemore/README.md @@ -0,0 +1,55 @@ +# The One Billion Row Challenge with Node.js + +## Run + +1. If needed, follow steps 1-2 in [Running the challenge](../../../../README.md#running-the-challenge) to create a `measurements.txt` file. + +1. Run: + +```bash +./calculate_average_havelessbemore.sh measurements.txt +``` + +## Benchmark + +### Results + +- Best: 14.8s +- Avg: 15-16s + +### Specs: + +- Machine: + + - MacBook Pro M2 + - RAM: 8 GB + - Cores: 8 (4 performance + 4 efficiency) + - OS: MacOS Sonoma +- Other + - NodeJS: v20.13.1 + - Web workers: 8 + - Input file: ~13.8 GB + +## Build + +If you'd like to rebuild the project: + +1. Navigate to the project subdirectory + +```bash +cd ./src/main/nodejs/havelessbemore +``` + +2. Install dev dependencies (TypeScript, bundler, etc) + +```bash +npm install +``` + +3. Build + +```bash +npm run build +``` + +Output will be in the `dist/` directory. Both CommonJs (`.cjs`) and ECMAScript (`.mjs`) modules are created. diff --git a/src/main/nodejs/havelessbemore/benchmarks/bench.ts b/src/main/nodejs/havelessbemore/benchmarks/bench.ts new file mode 100644 index 0000000..29146da --- /dev/null +++ b/src/main/nodejs/havelessbemore/benchmarks/bench.ts @@ -0,0 +1,58 @@ +import { mkdtemp, rm } from "fs/promises"; +import { join, resolve } from "path"; +import { stdout } from "process"; +import { availableParallelism, tmpdir } from "os"; +import { fileURLToPath } from "url"; + +import { Bench, Task } from "tinybench"; + +import { run } from "../src/main"; + +// INPUT +const filePath = process.argv[2]; +const maxWorkers = availableParallelism(); +const workerPath = resolve(fileURLToPath(import.meta.url), "../../dist/index.mjs"); + +// OUTPUT +const dir = await mkdtemp(join(tmpdir(), '1brc-')); + +// BENCHMARK +let i = 0; +let t0 = 0; +const bench = new Bench({ iterations: 5 }); +bench.add(`1BRC`, async () => { + const outPath = join(dir, `out_${i}.txt`); + return run(filePath, workerPath, maxWorkers, outPath); +}, { + beforeAll: () => { + t0 = performance.now(); + }, + beforeEach: function(): void { + const elapsed = toSeconds(performance.now() - t0); + console.log(`${this.name} (${elapsed}s): Running iteration ${++i}...`); + } +}); + +await bench.run(); + +// CLEANUP +await rm(dir, { recursive: true, force: true }); + +// REPORTING +function toRecord(task: Task): Record { + const out: Record = {}; + out["Name"] = task.name; + out["Min (s)"] = toSeconds(task.result?.min); + out["Max (s)"] = toSeconds(task.result?.max); + out["Avg (s)"] = toSeconds(task.result?.mean); + out["Samples"] = +(task.result?.samples ?? []).length; + return out; +} + +function toSeconds(ms: number | undefined): number { + return Math.floor(ms ?? 0) / 1000; +} + +console.table(bench.tasks.map(task => toRecord(task))); +const time = bench.tasks.reduce((sum, t) => sum + t.result!.totalTime, 0); +stdout.write(`Total time: ${toSeconds(time)}s\n`); \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs b/src/main/nodejs/havelessbemore/dist/index.cjs index 8e91dc3..ecb8d0f 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs +++ b/src/main/nodejs/havelessbemore/dist/index.cjs @@ -222,7 +222,7 @@ function print(tries, key, trieIndex, stream, separator = "", callbackFn) { } while (top >= 0); } -async function run$1(filePath, workerPath, maxWorkers) { +async function run$1(filePath, outPath, workerPath, maxWorkers) { maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS); const chunks = await getFileChunks( filePath, @@ -276,9 +276,9 @@ async function run$1(filePath, workerPath, maxWorkers) { for (let i = 2; i <= maxWorkers; ++i) { mergeLeft(tries, 1, i, mergeStations); } - const out = node_fs.createWriteStream("", { + const out = node_fs.createWriteStream(outPath, { flags: "a", - fd: 1, + fd: outPath.length < 1 ? 1 : void 0, highWaterMark: HIGH_WATER_MARK_OUT }); const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN); @@ -371,7 +371,7 @@ function parseDouble(b, min, max) { if (node_worker_threads.isMainThread) { const workerPath = node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))); - run$1(process.argv[2], workerPath, os.availableParallelism()); + run$1(process.argv[2], "", workerPath, os.availableParallelism()); } else { node_worker_threads.parentPort.addListener("message", async (req) => { const res = await run(req); diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs.map b/src/main/nodejs/havelessbemore/dist/index.cjs.map index 948663e..e04189e 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.cjs.map @@ -1 +1 @@ -{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/trie.ts","../src/utils/trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n/**\n * The maximum value of a byte for UTF-8 code points of up to 2 bytes.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_2B_MAX = 224;\n\n/**\n * The number of non-printable control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_PRINT_OFFSET = 32;\n\n/**\n * The number of printable byte values for UTF-8 code points of up to 2 bytes.\n */\nexport const UTF8_2B_PRINT_MAX = UTF8_2B_MAX - UTF8_PRINT_OFFSET;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_2B_PRINT_MAX } from \"./utf8\";\n\n// Trie static properties\n\n/**\n * Represents null / undefined.\n */\nexport const TRIE_NULL = 0;\n\n/**\n * The minimum size a trie.\n */\nexport const MIN_TRIE_SIZE = 524288; // 2 MiB\n\n/**\n * The default growth factor for growing the size of a trie.\n */\nexport const TRIE_GROWTH_FACTOR = 1.618; // ~phi\n\n/**\n * All trie properties are represented by 32 bits (4 bytes).\n */\nexport const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT;\n\n/**\n * The maximum number of children of any trie node.\n */\nexport const TRIE_MAX_CHILDREN = UTF8_2B_PRINT_MAX;\n\n// Trie child pointer properties\n\nexport const TRIE_CHILD_IDX_IDX = 0;\nexport const TRIE_CHILD_IDX_LEN = 1;\n\nexport const TRIE_CHILD_LEN = TRIE_CHILD_IDX_LEN;\n\n// Trie redirect pointer properties\n\nexport const TRIE_RED_ID_IDX = 0;\nexport const TRIE_RED_ID_LEN = 1;\n\nexport const TRIE_RED_VALUE_IDX_IDX = 1;\nexport const TRIE_RED_VALUE_IDX_LEN = 1;\n\nexport const TRIE_RED_LEN = TRIE_RED_ID_LEN + TRIE_RED_VALUE_IDX_LEN;\n\n// Trie node properties\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_LEN = 1;\n\nexport const TRIE_NODE_VALUE_ID_IDX = 1;\nexport const TRIE_NODE_VALUE_ID_LEN = 1;\n\nexport const TRIE_NODE_VALUE_IDX_IDX = 2;\nexport const TRIE_NODE_VALUE_IDX_LEN = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 3;\nexport const TRIE_NODE_CHILDREN_LEN = TRIE_CHILD_LEN * TRIE_MAX_CHILDREN;\n\nexport const TRIE_NODE_LEN =\n TRIE_NODE_ID_LEN +\n TRIE_NODE_VALUE_ID_LEN +\n TRIE_NODE_VALUE_IDX_LEN +\n TRIE_NODE_CHILDREN_LEN;\n\n// Trie properties\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_LEN = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_LEN = TRIE_NODE_LEN;\n\nexport const TRIE_HEADER_LEN = TRIE_SIZE_LEN + TRIE_ROOT_LEN;\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n MIN_TRIE_SIZE,\n TRIE_CHILD_LEN,\n TRIE_CHILD_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_HEADER_LEN,\n TRIE_ID_IDX,\n TRIE_MAX_CHILDREN,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_CHILDREN_LEN,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_LEN,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NODE_VALUE_ID_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_RED_LEN,\n TRIE_RED_VALUE_IDX_IDX,\n TRIE_RED_ID_IDX,\n} from \"../constants/trie\";\nimport { UTF8_PRINT_OFFSET } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX +\n TRIE_CHILD_LEN * (key[min++] - UTF8_PRINT_OFFSET);\n let child = trie[index + TRIE_CHILD_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_LEN > trie.length) {\n trie = grow(trie, child + TRIE_NODE_LEN);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_LEN;\n // Attach and initialize node\n trie[index + TRIE_CHILD_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array {\n const minSize = TRIE_HEADER_LEN;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (at: number, ai: number, bt: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvt = tries[bt][bi + TRIE_NODE_VALUE_ID_IDX];\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX];\n if (bvt !== TRIE_NULL) {\n // If left value is not null\n const avt = tries[at][ai + TRIE_NODE_VALUE_ID_IDX];\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX];\n if (avt !== TRIE_NULL) {\n mergeFn(avt, avi, bvt, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_ID_IDX] = bvt;\n tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_LEN;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_CHILD_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_RED_LEN > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_RED_LEN);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_RED_LEN;\n // Add new redirect\n tries[at][li + TRIE_RED_ID_IDX] = rt;\n tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n id: number,\n value: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, 0, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childKey, childPtr] = stack[top];\n\n // Check if end of children array\n if (childKey >= TRIE_MAX_CHILDREN) {\n --top;\n continue;\n }\n\n // Update stack top\n ++stack[top][1];\n stack[top][2] += TRIE_CHILD_LEN;\n\n // If just reached node\n if (childKey === 0) {\n // Check if the node has a value\n const nodeIndex = childPtr - TRIE_NODE_CHILDREN_IDX;\n const valueId = tries[trieI][nodeIndex + TRIE_NODE_VALUE_ID_IDX];\n if (valueId !== TRIE_NULL) {\n // Print the node's value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX];\n callbackFn(stream, key, top, valueId, valueIndex);\n }\n }\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX];\n if (childI !== TRIE_NULL) {\n // Resolve child if redirect\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX];\n trieI = childTrieI;\n }\n // Add the child to the stack\n key[top] = childKey + UTF8_PRINT_OFFSET;\n stack[++top] = [trieI, 0, childI + TRIE_NODE_CHILDREN_IDX];\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { ENTRY_MAX_LEN, STATION_NAME_MAX_LEN } from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/trie\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const counts: Uint32Array[] = new Array(maxWorkers + 1);\n const maxes: Int16Array[] = new Array(maxWorkers + 1);\n const mins: Int16Array[] = new Array(maxWorkers + 1);\n const sums: Float64Array[] = new Array(maxWorkers + 1);\n const tries: Int32Array[] = new Array(maxWorkers + 1);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i + 1;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({ end, filePath, id, start } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n const id = res.id;\n counts[id] = res.counts;\n maxes[id] = res.maxes;\n mins[id] = res.mins;\n sums[id] = res.sums;\n tries[id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 2; i <= maxWorkers; ++i) {\n mergeLeft(tries, 1, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(\"\", {\n flags: \"a\",\n fd: 1,\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 1, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(at: number, ai: number, bt: number, bi: number): void {\n counts[at][ai] += counts[bt][bi];\n maxes[at][ai] = Math.max(maxes[at][ai], maxes[bt][bi]);\n mins[at][ai] = Math.min(mins[at][ai], mins[bt][bi]);\n sums[at][ai] += sums[bt][bi];\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vt: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vt][vi] / counts[vt][vi]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vt][vi] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vt][vi] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport {\n TRIE_NODE_VALUE_ID_IDX,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NULL,\n} from \"./constants/trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n}: WorkerRequest): Promise {\n const counts = new Uint32Array(MAX_STATIONS);\n const maxes = new Int16Array(MAX_STATIONS);\n const mins = new Int16Array(MAX_STATIONS);\n const sums = new Float64Array(MAX_STATIONS);\n\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0), counts, maxes, mins, sums };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = 0;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_ID_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_ID_IDX] = id;\n trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n counts[index] = 1;\n maxes[index] = temp;\n mins[index] = temp;\n sums[index] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n ++counts[index];\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n sums[index] += temp;\n }\n\n return { id, trie, counts, maxes, mins, sums };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n return ++min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import os from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, os.availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [\n res.trie.buffer,\n res.counts.buffer,\n res.maxes.buffer,\n res.mins.buffer,\n res.sums.buffer,\n ]);\n });\n}\n"],"names":["open","at","bt","run","Worker","createWriteStream","createReadStream","isMainThread","fileURLToPath","runMain","parentPort","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/trie.ts","../src/utils/trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n/**\n * The maximum value of a byte for UTF-8 code points of up to 2 bytes.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_2B_MAX = 224;\n\n/**\n * The number of non-printable control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_PRINT_OFFSET = 32;\n\n/**\n * The number of printable byte values for UTF-8 code points of up to 2 bytes.\n */\nexport const UTF8_2B_PRINT_MAX = UTF8_2B_MAX - UTF8_PRINT_OFFSET;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_2B_PRINT_MAX } from \"./utf8\";\n\n// Trie static properties\n\n/**\n * Represents null / undefined.\n */\nexport const TRIE_NULL = 0;\n\n/**\n * The minimum size a trie.\n */\nexport const MIN_TRIE_SIZE = 524288; // 2 MiB\n\n/**\n * The default growth factor for growing the size of a trie.\n */\nexport const TRIE_GROWTH_FACTOR = 1.618; // ~phi\n\n/**\n * All trie properties are represented by 32 bits (4 bytes).\n */\nexport const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT;\n\n/**\n * The maximum number of children of any trie node.\n */\nexport const TRIE_MAX_CHILDREN = UTF8_2B_PRINT_MAX;\n\n// Trie child pointer properties\n\nexport const TRIE_CHILD_IDX_IDX = 0;\nexport const TRIE_CHILD_IDX_LEN = 1;\n\nexport const TRIE_CHILD_LEN = TRIE_CHILD_IDX_LEN;\n\n// Trie redirect pointer properties\n\nexport const TRIE_RED_ID_IDX = 0;\nexport const TRIE_RED_ID_LEN = 1;\n\nexport const TRIE_RED_VALUE_IDX_IDX = 1;\nexport const TRIE_RED_VALUE_IDX_LEN = 1;\n\nexport const TRIE_RED_LEN = TRIE_RED_ID_LEN + TRIE_RED_VALUE_IDX_LEN;\n\n// Trie node properties\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_LEN = 1;\n\nexport const TRIE_NODE_VALUE_ID_IDX = 1;\nexport const TRIE_NODE_VALUE_ID_LEN = 1;\n\nexport const TRIE_NODE_VALUE_IDX_IDX = 2;\nexport const TRIE_NODE_VALUE_IDX_LEN = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 3;\nexport const TRIE_NODE_CHILDREN_LEN = TRIE_CHILD_LEN * TRIE_MAX_CHILDREN;\n\nexport const TRIE_NODE_LEN =\n TRIE_NODE_ID_LEN +\n TRIE_NODE_VALUE_ID_LEN +\n TRIE_NODE_VALUE_IDX_LEN +\n TRIE_NODE_CHILDREN_LEN;\n\n// Trie properties\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_LEN = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_LEN = TRIE_NODE_LEN;\n\nexport const TRIE_HEADER_LEN = TRIE_SIZE_LEN + TRIE_ROOT_LEN;\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n MIN_TRIE_SIZE,\n TRIE_CHILD_LEN,\n TRIE_CHILD_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_HEADER_LEN,\n TRIE_ID_IDX,\n TRIE_MAX_CHILDREN,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_CHILDREN_LEN,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_LEN,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NODE_VALUE_ID_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_RED_LEN,\n TRIE_RED_VALUE_IDX_IDX,\n TRIE_RED_ID_IDX,\n} from \"../constants/trie\";\nimport { UTF8_PRINT_OFFSET } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX +\n TRIE_CHILD_LEN * (key[min++] - UTF8_PRINT_OFFSET);\n let child = trie[index + TRIE_CHILD_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_LEN > trie.length) {\n trie = grow(trie, child + TRIE_NODE_LEN);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_LEN;\n // Attach and initialize node\n trie[index + TRIE_CHILD_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array {\n const minSize = TRIE_HEADER_LEN;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (at: number, ai: number, bt: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvt = tries[bt][bi + TRIE_NODE_VALUE_ID_IDX];\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX];\n if (bvt !== TRIE_NULL) {\n // If left value is not null\n const avt = tries[at][ai + TRIE_NODE_VALUE_ID_IDX];\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX];\n if (avt !== TRIE_NULL) {\n mergeFn(avt, avi, bvt, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_ID_IDX] = bvt;\n tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_LEN;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_CHILD_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_RED_LEN > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_RED_LEN);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_RED_LEN;\n // Add new redirect\n tries[at][li + TRIE_RED_ID_IDX] = rt;\n tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n id: number,\n value: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, 0, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childKey, childPtr] = stack[top];\n\n // Check if end of children array\n if (childKey >= TRIE_MAX_CHILDREN) {\n --top;\n continue;\n }\n\n // Update stack top\n ++stack[top][1];\n stack[top][2] += TRIE_CHILD_LEN;\n\n // If just reached node\n if (childKey === 0) {\n // Check if the node has a value\n const nodeIndex = childPtr - TRIE_NODE_CHILDREN_IDX;\n const valueId = tries[trieI][nodeIndex + TRIE_NODE_VALUE_ID_IDX];\n if (valueId !== TRIE_NULL) {\n // Print the node's value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX];\n callbackFn(stream, key, top, valueId, valueIndex);\n }\n }\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX];\n if (childI !== TRIE_NULL) {\n // Resolve child if redirect\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX];\n trieI = childTrieI;\n }\n // Add the child to the stack\n key[top] = childKey + UTF8_PRINT_OFFSET;\n stack[++top] = [trieI, 0, childI + TRIE_NODE_CHILDREN_IDX];\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { ENTRY_MAX_LEN, STATION_NAME_MAX_LEN } from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/trie\";\n\nexport async function run(\n filePath: string,\n outPath: string,\n workerPath: string,\n maxWorkers: number,\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const counts: Uint32Array[] = new Array(maxWorkers + 1);\n const maxes: Int16Array[] = new Array(maxWorkers + 1);\n const mins: Int16Array[] = new Array(maxWorkers + 1);\n const sums: Float64Array[] = new Array(maxWorkers + 1);\n const tries: Int32Array[] = new Array(maxWorkers + 1);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i + 1;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({ end, filePath, id, start } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n const id = res.id;\n counts[id] = res.counts;\n maxes[id] = res.maxes;\n mins[id] = res.mins;\n sums[id] = res.sums;\n tries[id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 2; i <= maxWorkers; ++i) {\n mergeLeft(tries, 1, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n flags: \"a\",\n fd: (outPath.length < 1) ? 1 : undefined,\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 1, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(at: number, ai: number, bt: number, bi: number): void {\n counts[at][ai] += counts[bt][bi];\n maxes[at][ai] = Math.max(maxes[at][ai], maxes[bt][bi]);\n mins[at][ai] = Math.min(mins[at][ai], mins[bt][bi]);\n sums[at][ai] += sums[bt][bi];\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vt: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vt][vi] / counts[vt][vi]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vt][vi] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vt][vi] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport {\n TRIE_NODE_VALUE_ID_IDX,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NULL,\n} from \"./constants/trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n}: WorkerRequest): Promise {\n const counts = new Uint32Array(MAX_STATIONS);\n const maxes = new Int16Array(MAX_STATIONS);\n const mins = new Int16Array(MAX_STATIONS);\n const sums = new Float64Array(MAX_STATIONS);\n\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0), counts, maxes, mins, sums };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = 0;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_ID_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_ID_IDX] = id;\n trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n counts[index] = 1;\n maxes[index] = temp;\n mins[index] = temp;\n sums[index] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n ++counts[index];\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n sums[index] += temp;\n }\n\n return { id, trie, counts, maxes, mins, sums };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n return ++min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import os from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], \"\", workerPath, os.availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [\n res.trie.buffer,\n res.counts.buffer,\n res.maxes.buffer,\n res.mins.buffer,\n res.sums.buffer,\n ]);\n });\n}\n"],"names":["open","at","bt","run","Worker","createWriteStream","createReadStream","isMainThread","fileURLToPath","runMain","parentPort","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index ea363d7..8310ea0 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -219,7 +219,7 @@ function print(tries, key, trieIndex, stream, separator = "", callbackFn) { } while (top >= 0); } -async function run$1(filePath, workerPath, maxWorkers) { +async function run$1(filePath, outPath, workerPath, maxWorkers) { maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS); const chunks = await getFileChunks( filePath, @@ -273,9 +273,9 @@ async function run$1(filePath, workerPath, maxWorkers) { for (let i = 2; i <= maxWorkers; ++i) { mergeLeft(tries, 1, i, mergeStations); } - const out = createWriteStream("", { + const out = createWriteStream(outPath, { flags: "a", - fd: 1, + fd: outPath.length < 1 ? 1 : void 0, highWaterMark: HIGH_WATER_MARK_OUT }); const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN); @@ -368,7 +368,7 @@ function parseDouble(b, min, max) { if (isMainThread) { const workerPath = fileURLToPath(import.meta.url); - run$1(process.argv[2], workerPath, os.availableParallelism()); + run$1(process.argv[2], "", workerPath, os.availableParallelism()); } else { parentPort.addListener("message", async (req) => { const res = await run(req); diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index e0f84aa..bbbf5db 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1 +1 @@ -{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/trie.ts","../src/utils/trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n/**\n * The maximum value of a byte for UTF-8 code points of up to 2 bytes.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_2B_MAX = 224;\n\n/**\n * The number of non-printable control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_PRINT_OFFSET = 32;\n\n/**\n * The number of printable byte values for UTF-8 code points of up to 2 bytes.\n */\nexport const UTF8_2B_PRINT_MAX = UTF8_2B_MAX - UTF8_PRINT_OFFSET;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_2B_PRINT_MAX } from \"./utf8\";\n\n// Trie static properties\n\n/**\n * Represents null / undefined.\n */\nexport const TRIE_NULL = 0;\n\n/**\n * The minimum size a trie.\n */\nexport const MIN_TRIE_SIZE = 524288; // 2 MiB\n\n/**\n * The default growth factor for growing the size of a trie.\n */\nexport const TRIE_GROWTH_FACTOR = 1.618; // ~phi\n\n/**\n * All trie properties are represented by 32 bits (4 bytes).\n */\nexport const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT;\n\n/**\n * The maximum number of children of any trie node.\n */\nexport const TRIE_MAX_CHILDREN = UTF8_2B_PRINT_MAX;\n\n// Trie child pointer properties\n\nexport const TRIE_CHILD_IDX_IDX = 0;\nexport const TRIE_CHILD_IDX_LEN = 1;\n\nexport const TRIE_CHILD_LEN = TRIE_CHILD_IDX_LEN;\n\n// Trie redirect pointer properties\n\nexport const TRIE_RED_ID_IDX = 0;\nexport const TRIE_RED_ID_LEN = 1;\n\nexport const TRIE_RED_VALUE_IDX_IDX = 1;\nexport const TRIE_RED_VALUE_IDX_LEN = 1;\n\nexport const TRIE_RED_LEN = TRIE_RED_ID_LEN + TRIE_RED_VALUE_IDX_LEN;\n\n// Trie node properties\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_LEN = 1;\n\nexport const TRIE_NODE_VALUE_ID_IDX = 1;\nexport const TRIE_NODE_VALUE_ID_LEN = 1;\n\nexport const TRIE_NODE_VALUE_IDX_IDX = 2;\nexport const TRIE_NODE_VALUE_IDX_LEN = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 3;\nexport const TRIE_NODE_CHILDREN_LEN = TRIE_CHILD_LEN * TRIE_MAX_CHILDREN;\n\nexport const TRIE_NODE_LEN =\n TRIE_NODE_ID_LEN +\n TRIE_NODE_VALUE_ID_LEN +\n TRIE_NODE_VALUE_IDX_LEN +\n TRIE_NODE_CHILDREN_LEN;\n\n// Trie properties\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_LEN = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_LEN = TRIE_NODE_LEN;\n\nexport const TRIE_HEADER_LEN = TRIE_SIZE_LEN + TRIE_ROOT_LEN;\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n MIN_TRIE_SIZE,\n TRIE_CHILD_LEN,\n TRIE_CHILD_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_HEADER_LEN,\n TRIE_ID_IDX,\n TRIE_MAX_CHILDREN,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_CHILDREN_LEN,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_LEN,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NODE_VALUE_ID_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_RED_LEN,\n TRIE_RED_VALUE_IDX_IDX,\n TRIE_RED_ID_IDX,\n} from \"../constants/trie\";\nimport { UTF8_PRINT_OFFSET } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX +\n TRIE_CHILD_LEN * (key[min++] - UTF8_PRINT_OFFSET);\n let child = trie[index + TRIE_CHILD_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_LEN > trie.length) {\n trie = grow(trie, child + TRIE_NODE_LEN);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_LEN;\n // Attach and initialize node\n trie[index + TRIE_CHILD_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array {\n const minSize = TRIE_HEADER_LEN;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (at: number, ai: number, bt: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvt = tries[bt][bi + TRIE_NODE_VALUE_ID_IDX];\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX];\n if (bvt !== TRIE_NULL) {\n // If left value is not null\n const avt = tries[at][ai + TRIE_NODE_VALUE_ID_IDX];\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX];\n if (avt !== TRIE_NULL) {\n mergeFn(avt, avi, bvt, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_ID_IDX] = bvt;\n tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_LEN;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_CHILD_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_RED_LEN > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_RED_LEN);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_RED_LEN;\n // Add new redirect\n tries[at][li + TRIE_RED_ID_IDX] = rt;\n tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n id: number,\n value: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, 0, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childKey, childPtr] = stack[top];\n\n // Check if end of children array\n if (childKey >= TRIE_MAX_CHILDREN) {\n --top;\n continue;\n }\n\n // Update stack top\n ++stack[top][1];\n stack[top][2] += TRIE_CHILD_LEN;\n\n // If just reached node\n if (childKey === 0) {\n // Check if the node has a value\n const nodeIndex = childPtr - TRIE_NODE_CHILDREN_IDX;\n const valueId = tries[trieI][nodeIndex + TRIE_NODE_VALUE_ID_IDX];\n if (valueId !== TRIE_NULL) {\n // Print the node's value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX];\n callbackFn(stream, key, top, valueId, valueIndex);\n }\n }\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX];\n if (childI !== TRIE_NULL) {\n // Resolve child if redirect\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX];\n trieI = childTrieI;\n }\n // Add the child to the stack\n key[top] = childKey + UTF8_PRINT_OFFSET;\n stack[++top] = [trieI, 0, childI + TRIE_NODE_CHILDREN_IDX];\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { ENTRY_MAX_LEN, STATION_NAME_MAX_LEN } from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/trie\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const counts: Uint32Array[] = new Array(maxWorkers + 1);\n const maxes: Int16Array[] = new Array(maxWorkers + 1);\n const mins: Int16Array[] = new Array(maxWorkers + 1);\n const sums: Float64Array[] = new Array(maxWorkers + 1);\n const tries: Int32Array[] = new Array(maxWorkers + 1);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i + 1;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({ end, filePath, id, start } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n const id = res.id;\n counts[id] = res.counts;\n maxes[id] = res.maxes;\n mins[id] = res.mins;\n sums[id] = res.sums;\n tries[id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 2; i <= maxWorkers; ++i) {\n mergeLeft(tries, 1, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(\"\", {\n flags: \"a\",\n fd: 1,\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 1, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(at: number, ai: number, bt: number, bi: number): void {\n counts[at][ai] += counts[bt][bi];\n maxes[at][ai] = Math.max(maxes[at][ai], maxes[bt][bi]);\n mins[at][ai] = Math.min(mins[at][ai], mins[bt][bi]);\n sums[at][ai] += sums[bt][bi];\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vt: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vt][vi] / counts[vt][vi]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vt][vi] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vt][vi] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport {\n TRIE_NODE_VALUE_ID_IDX,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NULL,\n} from \"./constants/trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n}: WorkerRequest): Promise {\n const counts = new Uint32Array(MAX_STATIONS);\n const maxes = new Int16Array(MAX_STATIONS);\n const mins = new Int16Array(MAX_STATIONS);\n const sums = new Float64Array(MAX_STATIONS);\n\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0), counts, maxes, mins, sums };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = 0;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_ID_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_ID_IDX] = id;\n trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n counts[index] = 1;\n maxes[index] = temp;\n mins[index] = temp;\n sums[index] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n ++counts[index];\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n sums[index] += temp;\n }\n\n return { id, trie, counts, maxes, mins, sums };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n return ++min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import os from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, os.availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [\n res.trie.buffer,\n res.counts.buffer,\n res.maxes.buffer,\n res.mins.buffer,\n res.sums.buffer,\n ]);\n });\n}\n"],"names":["at","bt","run","runMain","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/trie.ts","../src/utils/trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n/**\n * The maximum value of a byte for UTF-8 code points of up to 2 bytes.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_2B_MAX = 224;\n\n/**\n * The number of non-printable control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_PRINT_OFFSET = 32;\n\n/**\n * The number of printable byte values for UTF-8 code points of up to 2 bytes.\n */\nexport const UTF8_2B_PRINT_MAX = UTF8_2B_MAX - UTF8_PRINT_OFFSET;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_2B_PRINT_MAX } from \"./utf8\";\n\n// Trie static properties\n\n/**\n * Represents null / undefined.\n */\nexport const TRIE_NULL = 0;\n\n/**\n * The minimum size a trie.\n */\nexport const MIN_TRIE_SIZE = 524288; // 2 MiB\n\n/**\n * The default growth factor for growing the size of a trie.\n */\nexport const TRIE_GROWTH_FACTOR = 1.618; // ~phi\n\n/**\n * All trie properties are represented by 32 bits (4 bytes).\n */\nexport const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT;\n\n/**\n * The maximum number of children of any trie node.\n */\nexport const TRIE_MAX_CHILDREN = UTF8_2B_PRINT_MAX;\n\n// Trie child pointer properties\n\nexport const TRIE_CHILD_IDX_IDX = 0;\nexport const TRIE_CHILD_IDX_LEN = 1;\n\nexport const TRIE_CHILD_LEN = TRIE_CHILD_IDX_LEN;\n\n// Trie redirect pointer properties\n\nexport const TRIE_RED_ID_IDX = 0;\nexport const TRIE_RED_ID_LEN = 1;\n\nexport const TRIE_RED_VALUE_IDX_IDX = 1;\nexport const TRIE_RED_VALUE_IDX_LEN = 1;\n\nexport const TRIE_RED_LEN = TRIE_RED_ID_LEN + TRIE_RED_VALUE_IDX_LEN;\n\n// Trie node properties\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_LEN = 1;\n\nexport const TRIE_NODE_VALUE_ID_IDX = 1;\nexport const TRIE_NODE_VALUE_ID_LEN = 1;\n\nexport const TRIE_NODE_VALUE_IDX_IDX = 2;\nexport const TRIE_NODE_VALUE_IDX_LEN = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 3;\nexport const TRIE_NODE_CHILDREN_LEN = TRIE_CHILD_LEN * TRIE_MAX_CHILDREN;\n\nexport const TRIE_NODE_LEN =\n TRIE_NODE_ID_LEN +\n TRIE_NODE_VALUE_ID_LEN +\n TRIE_NODE_VALUE_IDX_LEN +\n TRIE_NODE_CHILDREN_LEN;\n\n// Trie properties\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_LEN = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_LEN = TRIE_NODE_LEN;\n\nexport const TRIE_HEADER_LEN = TRIE_SIZE_LEN + TRIE_ROOT_LEN;\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n MIN_TRIE_SIZE,\n TRIE_CHILD_LEN,\n TRIE_CHILD_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_HEADER_LEN,\n TRIE_ID_IDX,\n TRIE_MAX_CHILDREN,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_CHILDREN_LEN,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_LEN,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NODE_VALUE_ID_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_RED_LEN,\n TRIE_RED_VALUE_IDX_IDX,\n TRIE_RED_ID_IDX,\n} from \"../constants/trie\";\nimport { UTF8_PRINT_OFFSET } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX +\n TRIE_CHILD_LEN * (key[min++] - UTF8_PRINT_OFFSET);\n let child = trie[index + TRIE_CHILD_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_LEN > trie.length) {\n trie = grow(trie, child + TRIE_NODE_LEN);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_LEN;\n // Attach and initialize node\n trie[index + TRIE_CHILD_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array {\n const minSize = TRIE_HEADER_LEN;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (at: number, ai: number, bt: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvt = tries[bt][bi + TRIE_NODE_VALUE_ID_IDX];\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX];\n if (bvt !== TRIE_NULL) {\n // If left value is not null\n const avt = tries[at][ai + TRIE_NODE_VALUE_ID_IDX];\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX];\n if (avt !== TRIE_NULL) {\n mergeFn(avt, avi, bvt, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_ID_IDX] = bvt;\n tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_LEN;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_CHILD_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_RED_LEN > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_RED_LEN);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_RED_LEN;\n // Add new redirect\n tries[at][li + TRIE_RED_ID_IDX] = rt;\n tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n id: number,\n value: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, 0, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childKey, childPtr] = stack[top];\n\n // Check if end of children array\n if (childKey >= TRIE_MAX_CHILDREN) {\n --top;\n continue;\n }\n\n // Update stack top\n ++stack[top][1];\n stack[top][2] += TRIE_CHILD_LEN;\n\n // If just reached node\n if (childKey === 0) {\n // Check if the node has a value\n const nodeIndex = childPtr - TRIE_NODE_CHILDREN_IDX;\n const valueId = tries[trieI][nodeIndex + TRIE_NODE_VALUE_ID_IDX];\n if (valueId !== TRIE_NULL) {\n // Print the node's value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX];\n callbackFn(stream, key, top, valueId, valueIndex);\n }\n }\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX];\n if (childI !== TRIE_NULL) {\n // Resolve child if redirect\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX];\n trieI = childTrieI;\n }\n // Add the child to the stack\n key[top] = childKey + UTF8_PRINT_OFFSET;\n stack[++top] = [trieI, 0, childI + TRIE_NODE_CHILDREN_IDX];\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { ENTRY_MAX_LEN, STATION_NAME_MAX_LEN } from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/trie\";\n\nexport async function run(\n filePath: string,\n outPath: string,\n workerPath: string,\n maxWorkers: number,\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const counts: Uint32Array[] = new Array(maxWorkers + 1);\n const maxes: Int16Array[] = new Array(maxWorkers + 1);\n const mins: Int16Array[] = new Array(maxWorkers + 1);\n const sums: Float64Array[] = new Array(maxWorkers + 1);\n const tries: Int32Array[] = new Array(maxWorkers + 1);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i + 1;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({ end, filePath, id, start } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n const id = res.id;\n counts[id] = res.counts;\n maxes[id] = res.maxes;\n mins[id] = res.mins;\n sums[id] = res.sums;\n tries[id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 2; i <= maxWorkers; ++i) {\n mergeLeft(tries, 1, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n flags: \"a\",\n fd: (outPath.length < 1) ? 1 : undefined,\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 1, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(at: number, ai: number, bt: number, bi: number): void {\n counts[at][ai] += counts[bt][bi];\n maxes[at][ai] = Math.max(maxes[at][ai], maxes[bt][bi]);\n mins[at][ai] = Math.min(mins[at][ai], mins[bt][bi]);\n sums[at][ai] += sums[bt][bi];\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vt: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vt][vi] / counts[vt][vi]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vt][vi] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vt][vi] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport {\n TRIE_NODE_VALUE_ID_IDX,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NULL,\n} from \"./constants/trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n}: WorkerRequest): Promise {\n const counts = new Uint32Array(MAX_STATIONS);\n const maxes = new Int16Array(MAX_STATIONS);\n const mins = new Int16Array(MAX_STATIONS);\n const sums = new Float64Array(MAX_STATIONS);\n\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0), counts, maxes, mins, sums };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = 0;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_ID_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_ID_IDX] = id;\n trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n counts[index] = 1;\n maxes[index] = temp;\n mins[index] = temp;\n sums[index] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n ++counts[index];\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n sums[index] += temp;\n }\n\n return { id, trie, counts, maxes, mins, sums };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n return ++min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import os from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], \"\", workerPath, os.availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [\n res.trie.buffer,\n res.counts.buffer,\n res.maxes.buffer,\n res.mins.buffer,\n res.sums.buffer,\n ]);\n });\n}\n"],"names":["at","bt","run","runMain","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/package-lock.json b/src/main/nodejs/havelessbemore/package-lock.json index 89be3a8..3ff8fa1 100644 --- a/src/main/nodejs/havelessbemore/package-lock.json +++ b/src/main/nodejs/havelessbemore/package-lock.json @@ -14,7 +14,9 @@ "rimraf": "^5.0.7", "rollup": "^4.17.2", "rollup-plugin-esbuild": "^6.1.1", + "tinybench": "^2.8.0", "tslib": "^2.6.2", + "tsx": "^4.10.5", "typescript": "^5.4.5", "typescript-eslint": "^7.10.0" }, @@ -2623,6 +2625,12 @@ "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, + "node_modules/tinybench": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.8.0.tgz", + "integrity": "sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw==", + "dev": true + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -2653,6 +2661,431 @@ "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", "dev": true }, + "node_modules/tsx": { + "version": "4.10.5", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.10.5.tgz", + "integrity": "sha512-twDSbf7Gtea4I2copqovUiNTEDrT8XNFXsuHpfGbdpW/z9ZW4fTghzzhAG0WfrCuJmJiOEY1nLIjq4u3oujRWQ==", + "dev": true, + "dependencies": { + "esbuild": "~0.20.2", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/tsx/node_modules/@esbuild/aix-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", + "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", + "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", + "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/android-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", + "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", + "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/darwin-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", + "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", + "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", + "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", + "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", + "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", + "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-loong64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", + "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", + "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", + "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", + "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-s390x": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", + "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", + "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", + "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", + "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/sunos-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", + "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-arm64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", + "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-ia32": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", + "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-x64": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", + "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/esbuild": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", + "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.20.2", + "@esbuild/android-arm": "0.20.2", + "@esbuild/android-arm64": "0.20.2", + "@esbuild/android-x64": "0.20.2", + "@esbuild/darwin-arm64": "0.20.2", + "@esbuild/darwin-x64": "0.20.2", + "@esbuild/freebsd-arm64": "0.20.2", + "@esbuild/freebsd-x64": "0.20.2", + "@esbuild/linux-arm": "0.20.2", + "@esbuild/linux-arm64": "0.20.2", + "@esbuild/linux-ia32": "0.20.2", + "@esbuild/linux-loong64": "0.20.2", + "@esbuild/linux-mips64el": "0.20.2", + "@esbuild/linux-ppc64": "0.20.2", + "@esbuild/linux-riscv64": "0.20.2", + "@esbuild/linux-s390x": "0.20.2", + "@esbuild/linux-x64": "0.20.2", + "@esbuild/netbsd-x64": "0.20.2", + "@esbuild/openbsd-x64": "0.20.2", + "@esbuild/sunos-x64": "0.20.2", + "@esbuild/win32-arm64": "0.20.2", + "@esbuild/win32-ia32": "0.20.2", + "@esbuild/win32-x64": "0.20.2" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/src/main/nodejs/havelessbemore/package.json b/src/main/nodejs/havelessbemore/package.json index bbcd382..95ac107 100644 --- a/src/main/nodejs/havelessbemore/package.json +++ b/src/main/nodejs/havelessbemore/package.json @@ -15,6 +15,7 @@ } }, "scripts": { + "bench": "tsx ./benchmarks/bench.ts ../../../../measurements.txt", "build": "rimraf dist && tsc && rollup -c --configPlugin typescript", "format": "prettier . --write", "lint": "eslint" @@ -29,7 +30,9 @@ "rimraf": "^5.0.7", "rollup": "^4.17.2", "rollup-plugin-esbuild": "^6.1.1", + "tinybench": "^2.8.0", "tslib": "^2.6.2", + "tsx": "^4.10.5", "typescript": "^5.4.5", "typescript-eslint": "^7.10.0" } diff --git a/src/main/nodejs/havelessbemore/src/index.ts b/src/main/nodejs/havelessbemore/src/index.ts index e404108..4a2c785 100644 --- a/src/main/nodejs/havelessbemore/src/index.ts +++ b/src/main/nodejs/havelessbemore/src/index.ts @@ -1,4 +1,4 @@ -import os from "node:os"; +import { availableParallelism } from "node:os"; import { fileURLToPath } from "node:url"; import { isMainThread, parentPort } from "node:worker_threads"; @@ -9,7 +9,7 @@ import { run as runWorker } from "./worker"; if (isMainThread) { const workerPath = fileURLToPath(import.meta.url); - runMain(process.argv[2], workerPath, os.availableParallelism()); + runMain(process.argv[2], workerPath, availableParallelism()); } else { parentPort!.addListener("message", async (req: WorkerRequest) => { const res = await runWorker(req); diff --git a/src/main/nodejs/havelessbemore/src/main.ts b/src/main/nodejs/havelessbemore/src/main.ts index 22296b3..7be98df 100644 --- a/src/main/nodejs/havelessbemore/src/main.ts +++ b/src/main/nodejs/havelessbemore/src/main.ts @@ -14,6 +14,7 @@ export async function run( filePath: string, workerPath: string, maxWorkers: number, + outPath = "" ): Promise { // Sanitize number of workers maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS); @@ -87,9 +88,9 @@ export async function run( } // Print results - const out = createWriteStream("", { + const out = createWriteStream(outPath, { + fd: (outPath.length < 1) ? 1 : undefined, flags: "a", - fd: 1, highWaterMark: HIGH_WATER_MARK_OUT, }); const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN); diff --git a/src/main/nodejs/havelessbemore/tsconfig.json b/src/main/nodejs/havelessbemore/tsconfig.json index 2956e64..f5c0f23 100644 --- a/src/main/nodejs/havelessbemore/tsconfig.json +++ b/src/main/nodejs/havelessbemore/tsconfig.json @@ -111,5 +111,5 @@ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ "skipLibCheck": true /* Skip type checking all .d.ts files. */ }, - "include": ["src", "./*.config.ts"] + "include": ["benchmarks", "src", "./*.config.ts"] } From d23d1c227280f38ae9899fe1210e35842d075dd8 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Wed, 22 May 2024 09:33:26 -0400 Subject: [PATCH 04/69] Flatten value arrays from 1 per worker to 1 global. Allows removal of a trie node property, reducing trie memory --- src/main/nodejs/havelessbemore/README.md | 1 + .../nodejs/havelessbemore/benchmarks/bench.ts | 47 ++++--- src/main/nodejs/havelessbemore/dist/index.cjs | 119 +++++++++--------- .../nodejs/havelessbemore/dist/index.cjs.map | 2 +- src/main/nodejs/havelessbemore/dist/index.mjs | 119 +++++++++--------- .../nodejs/havelessbemore/dist/index.mjs.map | 2 +- .../havelessbemore/src/constants/trie.ts | 12 +- src/main/nodejs/havelessbemore/src/index.ts | 8 +- src/main/nodejs/havelessbemore/src/main.ts | 67 +++++----- .../havelessbemore/src/types/workerRequest.ts | 5 + .../src/types/workerResponse.ts | 4 - .../nodejs/havelessbemore/src/utils/trie.ts | 23 ++-- src/main/nodejs/havelessbemore/src/worker.ts | 25 ++-- 13 files changed, 213 insertions(+), 221 deletions(-) diff --git a/src/main/nodejs/havelessbemore/README.md b/src/main/nodejs/havelessbemore/README.md index d0f4467..5ef3550 100644 --- a/src/main/nodejs/havelessbemore/README.md +++ b/src/main/nodejs/havelessbemore/README.md @@ -25,6 +25,7 @@ - RAM: 8 GB - Cores: 8 (4 performance + 4 efficiency) - OS: MacOS Sonoma + - Other - NodeJS: v20.13.1 - Web workers: 8 diff --git a/src/main/nodejs/havelessbemore/benchmarks/bench.ts b/src/main/nodejs/havelessbemore/benchmarks/bench.ts index 29146da..83b2c3d 100644 --- a/src/main/nodejs/havelessbemore/benchmarks/bench.ts +++ b/src/main/nodejs/havelessbemore/benchmarks/bench.ts @@ -11,27 +11,34 @@ import { run } from "../src/main"; // INPUT const filePath = process.argv[2]; const maxWorkers = availableParallelism(); -const workerPath = resolve(fileURLToPath(import.meta.url), "../../dist/index.mjs"); +const workerPath = resolve( + fileURLToPath(import.meta.url), + "../../dist/index.mjs", +); // OUTPUT -const dir = await mkdtemp(join(tmpdir(), '1brc-')); +const dir = await mkdtemp(join(tmpdir(), "1brc-")); // BENCHMARK let i = 0; let t0 = 0; const bench = new Bench({ iterations: 5 }); -bench.add(`1BRC`, async () => { +bench.add( + `1BRC`, + async () => { const outPath = join(dir, `out_${i}.txt`); return run(filePath, workerPath, maxWorkers, outPath); -}, { + }, + { beforeAll: () => { - t0 = performance.now(); + t0 = performance.now(); }, - beforeEach: function(): void { - const elapsed = toSeconds(performance.now() - t0); - console.log(`${this.name} (${elapsed}s): Running iteration ${++i}...`); - } -}); + beforeEach: function (): void { + const elapsed = toSeconds(performance.now() - t0); + console.log(`${this.name} (${elapsed}s): Running iteration ${++i}...`); + }, + }, +); await bench.run(); @@ -40,19 +47,19 @@ await rm(dir, { recursive: true, force: true }); // REPORTING function toRecord(task: Task): Record { - const out: Record = {}; - out["Name"] = task.name; - out["Min (s)"] = toSeconds(task.result?.min); - out["Max (s)"] = toSeconds(task.result?.max); - out["Avg (s)"] = toSeconds(task.result?.mean); - out["Samples"] = +(task.result?.samples ?? []).length; - return out; + const out: Record = {}; + out["Name"] = task.name; + out["Min (s)"] = toSeconds(task.result?.min); + out["Max (s)"] = toSeconds(task.result?.max); + out["Avg (s)"] = toSeconds(task.result?.mean); + out["Samples"] = +(task.result?.samples ?? []).length; + return out; } function toSeconds(ms: number | undefined): number { - return Math.floor(ms ?? 0) / 1000; + return Math.floor(ms ?? 0) / 1000; } -console.table(bench.tasks.map(task => toRecord(task))); +console.table(bench.tasks.map((task) => toRecord(task))); const time = bench.tasks.reduce((sum, t) => sum + t.result!.totalTime, 0); -stdout.write(`Total time: ${toSeconds(time)}s\n`); \ No newline at end of file +stdout.write(`Total time: ${toSeconds(time)}s\n`); diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs b/src/main/nodejs/havelessbemore/dist/index.cjs index ecb8d0f..69efdc5 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs +++ b/src/main/nodejs/havelessbemore/dist/index.cjs @@ -1,6 +1,6 @@ 'use strict'; -var os = require('node:os'); +var node_os = require('node:os'); var node_url = require('node:url'); var node_worker_threads = require('node:worker_threads'); var node_fs = require('node:fs'); @@ -79,13 +79,11 @@ const TRIE_RED_VALUE_IDX_LEN = 1; const TRIE_RED_LEN = TRIE_RED_ID_LEN + TRIE_RED_VALUE_IDX_LEN; const TRIE_NODE_ID_IDX = 0; const TRIE_NODE_ID_LEN = 1; -const TRIE_NODE_VALUE_ID_IDX = 1; -const TRIE_NODE_VALUE_ID_LEN = 1; -const TRIE_NODE_VALUE_IDX_IDX = 2; +const TRIE_NODE_VALUE_IDX_IDX = 1; const TRIE_NODE_VALUE_IDX_LEN = 1; -const TRIE_NODE_CHILDREN_IDX = 3; +const TRIE_NODE_CHILDREN_IDX = 2; const TRIE_NODE_CHILDREN_LEN = TRIE_CHILD_LEN * TRIE_MAX_CHILDREN; -const TRIE_NODE_LEN = TRIE_NODE_ID_LEN + TRIE_NODE_VALUE_ID_LEN + TRIE_NODE_VALUE_IDX_LEN + TRIE_NODE_CHILDREN_LEN; +const TRIE_NODE_LEN = TRIE_NODE_ID_LEN + TRIE_NODE_VALUE_IDX_LEN + TRIE_NODE_CHILDREN_LEN; const TRIE_SIZE_IDX = 0; const TRIE_SIZE_LEN = 1; const TRIE_ROOT_IDX = 1; @@ -119,6 +117,7 @@ function createTrie(id = 0, size = MIN_TRIE_SIZE) { return trie; } function grow(trie, minSize = 0) { + console.log("D"); const length = trie[TRIE_SIZE_IDX]; minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR)); const next = new Int32Array(minSize); @@ -135,15 +134,12 @@ function mergeLeft(tries, at, bt, mergeFn) { const Q = queue.length; for (let q = 0; q < Q; ++q) { let [at2, ai, bt2, bi] = queue[q]; - const bvt = tries[bt2][bi + TRIE_NODE_VALUE_ID_IDX]; const bvi = tries[bt2][bi + TRIE_NODE_VALUE_IDX_IDX]; - if (bvt !== TRIE_NULL) { - const avt = tries[at2][ai + TRIE_NODE_VALUE_ID_IDX]; + if (bvi !== TRIE_NULL) { const avi = tries[at2][ai + TRIE_NODE_VALUE_IDX_IDX]; - if (avt !== TRIE_NULL) { - mergeFn(avt, avi, bvt, bvi); + if (avi !== TRIE_NULL) { + mergeFn(avi, bvi); } else { - tries[at2][ai + TRIE_NODE_VALUE_ID_IDX] = bvt; tries[at2][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi; } } @@ -199,14 +195,13 @@ function print(tries, key, trieIndex, stream, separator = "", callbackFn) { stack[top][2] += TRIE_CHILD_LEN; if (childKey === 0) { const nodeIndex = childPtr - TRIE_NODE_CHILDREN_IDX; - const valueId = tries[trieI][nodeIndex + TRIE_NODE_VALUE_ID_IDX]; - if (valueId !== TRIE_NULL) { + const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX]; + if (valueIndex !== TRIE_NULL) { if (tail) { stream.write(separator); } tail = true; - const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX]; - callbackFn(stream, key, top, valueId, valueIndex); + callbackFn(stream, key, top, valueIndex); } } let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX]; @@ -222,7 +217,7 @@ function print(tries, key, trieIndex, stream, separator = "", callbackFn) { } while (top >= 0); } -async function run$1(filePath, outPath, workerPath, maxWorkers) { +async function run$1(filePath, workerPath, maxWorkers, outPath = "") { maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS); const chunks = await getFileChunks( filePath, @@ -231,11 +226,15 @@ async function run$1(filePath, outPath, workerPath, maxWorkers) { CHUNK_SIZE_MIN ); maxWorkers = chunks.length; - const counts = new Array(maxWorkers + 1); - const maxes = new Array(maxWorkers + 1); - const mins = new Array(maxWorkers + 1); - const sums = new Array(maxWorkers + 1); - const tries = new Array(maxWorkers + 1); + const numVals = MAX_STATIONS * maxWorkers + 1; + let bpe = Uint32Array.BYTES_PER_ELEMENT; + const counts = new Uint32Array(new SharedArrayBuffer(bpe * numVals)); + bpe = Int16Array.BYTES_PER_ELEMENT; + const maxes = new Int16Array(new SharedArrayBuffer(bpe * numVals)); + const mins = new Int16Array(new SharedArrayBuffer(bpe * numVals)); + bpe = Float64Array.BYTES_PER_ELEMENT; + const sums = new Float64Array(new SharedArrayBuffer(bpe * numVals)); + const tries = new Array(maxWorkers); const workers = new Array(maxWorkers); for (let i = 0; i < maxWorkers; ++i) { const worker = new node_worker_threads.Worker(workerPath); @@ -254,52 +253,56 @@ async function run$1(filePath, outPath, workerPath, maxWorkers) { } const tasks = new Array(maxWorkers); for (let i = 0; i < maxWorkers; ++i) { - const id = i + 1; + const id = i; const worker = workers[i]; const [start, end] = chunks[i]; tasks[i] = new Promise((resolve) => { worker.once("message", resolve); - worker.postMessage({ end, filePath, id, start }); + worker.postMessage({ + counts, + end, + filePath, + id, + maxes, + mins, + start, + sums + }); }); } for await (const res of tasks) { - const id = res.id; - counts[id] = res.counts; - maxes[id] = res.maxes; - mins[id] = res.mins; - sums[id] = res.sums; - tries[id] = res.trie; + tries[res.id] = res.trie; } for (let i = 0; i < maxWorkers; ++i) { await workers[i].terminate(); } - for (let i = 2; i <= maxWorkers; ++i) { - mergeLeft(tries, 1, i, mergeStations); + for (let i = 1; i < maxWorkers; ++i) { + mergeLeft(tries, 0, i, mergeStations); } const out = node_fs.createWriteStream(outPath, { - flags: "a", fd: outPath.length < 1 ? 1 : void 0, + flags: "a", highWaterMark: HIGH_WATER_MARK_OUT }); const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN); out.write("{"); - print(tries, buffer, 1, out, ", ", printStation); + print(tries, buffer, 0, out, ", ", printStation); out.end("}\n"); - function mergeStations(at, ai, bt, bi) { - counts[at][ai] += counts[bt][bi]; - maxes[at][ai] = Math.max(maxes[at][ai], maxes[bt][bi]); - mins[at][ai] = Math.min(mins[at][ai], mins[bt][bi]); - sums[at][ai] += sums[bt][bi]; + function mergeStations(ai, bi) { + counts[ai] += counts[bi]; + maxes[ai] = Math.max(maxes[ai], maxes[bi]); + mins[ai] = Math.min(mins[ai], mins[bi]); + sums[ai] += sums[bi]; } - function printStation(stream, name, nameLen, vt, vi) { - const avg = Math.round(sums[vt][vi] / counts[vt][vi]); + function printStation(stream, name, nameLen, vi) { + const avg = Math.round(sums[vi] / counts[vi]); stream.write(name.toString("utf8", 0, nameLen)); stream.write("="); - stream.write((mins[vt][vi] / 10).toFixed(1)); + stream.write((mins[vi] / 10).toFixed(1)); stream.write("/"); stream.write((avg / 10).toFixed(1)); stream.write("/"); - stream.write((maxes[vt][vi] / 10).toFixed(1)); + stream.write((maxes[vi] / 10).toFixed(1)); } } @@ -307,17 +310,18 @@ async function run({ end, filePath, id, - start + start, + // Shared memory + counts, + maxes, + mins, + sums }) { - const counts = new Uint32Array(MAX_STATIONS); - const maxes = new Int16Array(MAX_STATIONS); - const mins = new Int16Array(MAX_STATIONS); - const sums = new Float64Array(MAX_STATIONS); if (start >= end) { - return { id, trie: createTrie(id, 0), counts, maxes, mins, sums }; + return { id, trie: createTrie(id, 0) }; } let trie = createTrie(id); - let stations = 0; + let stations = id * MAX_STATIONS + 1; const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN); const stream = node_fs.createReadStream(filePath, { start, @@ -338,10 +342,9 @@ async function run({ const tempV = parseDouble(buffer, tempI, bufI); bufI = 0; [trie, leaf] = add(trie, buffer, 0, tempI); - if (trie[leaf + TRIE_NODE_VALUE_ID_IDX] !== TRIE_NULL) { + if (trie[leaf + TRIE_NODE_VALUE_IDX_IDX] !== TRIE_NULL) { updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV); } else { - trie[leaf + TRIE_NODE_VALUE_ID_IDX] = id; trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations; newStation(stations++, tempV); } @@ -360,7 +363,7 @@ async function run({ mins[index] = mins[index] <= temp ? mins[index] : temp; sums[index] += temp; } - return { id, trie, counts, maxes, mins, sums }; + return { id, trie }; } function parseDouble(b, min, max) { if (b[min] === CHAR_MINUS) { @@ -371,17 +374,11 @@ function parseDouble(b, min, max) { if (node_worker_threads.isMainThread) { const workerPath = node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))); - run$1(process.argv[2], "", workerPath, os.availableParallelism()); + run$1(process.argv[2], workerPath, node_os.availableParallelism()); } else { node_worker_threads.parentPort.addListener("message", async (req) => { const res = await run(req); - node_worker_threads.parentPort.postMessage(res, [ - res.trie.buffer, - res.counts.buffer, - res.maxes.buffer, - res.mins.buffer, - res.sums.buffer - ]); + node_worker_threads.parentPort.postMessage(res, [res.trie.buffer]); }); } //# sourceMappingURL=index.cjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs.map b/src/main/nodejs/havelessbemore/dist/index.cjs.map index e04189e..18c267c 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.cjs.map @@ -1 +1 @@ -{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/trie.ts","../src/utils/trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n/**\n * The maximum value of a byte for UTF-8 code points of up to 2 bytes.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_2B_MAX = 224;\n\n/**\n * The number of non-printable control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_PRINT_OFFSET = 32;\n\n/**\n * The number of printable byte values for UTF-8 code points of up to 2 bytes.\n */\nexport const UTF8_2B_PRINT_MAX = UTF8_2B_MAX - UTF8_PRINT_OFFSET;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_2B_PRINT_MAX } from \"./utf8\";\n\n// Trie static properties\n\n/**\n * Represents null / undefined.\n */\nexport const TRIE_NULL = 0;\n\n/**\n * The minimum size a trie.\n */\nexport const MIN_TRIE_SIZE = 524288; // 2 MiB\n\n/**\n * The default growth factor for growing the size of a trie.\n */\nexport const TRIE_GROWTH_FACTOR = 1.618; // ~phi\n\n/**\n * All trie properties are represented by 32 bits (4 bytes).\n */\nexport const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT;\n\n/**\n * The maximum number of children of any trie node.\n */\nexport const TRIE_MAX_CHILDREN = UTF8_2B_PRINT_MAX;\n\n// Trie child pointer properties\n\nexport const TRIE_CHILD_IDX_IDX = 0;\nexport const TRIE_CHILD_IDX_LEN = 1;\n\nexport const TRIE_CHILD_LEN = TRIE_CHILD_IDX_LEN;\n\n// Trie redirect pointer properties\n\nexport const TRIE_RED_ID_IDX = 0;\nexport const TRIE_RED_ID_LEN = 1;\n\nexport const TRIE_RED_VALUE_IDX_IDX = 1;\nexport const TRIE_RED_VALUE_IDX_LEN = 1;\n\nexport const TRIE_RED_LEN = TRIE_RED_ID_LEN + TRIE_RED_VALUE_IDX_LEN;\n\n// Trie node properties\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_LEN = 1;\n\nexport const TRIE_NODE_VALUE_ID_IDX = 1;\nexport const TRIE_NODE_VALUE_ID_LEN = 1;\n\nexport const TRIE_NODE_VALUE_IDX_IDX = 2;\nexport const TRIE_NODE_VALUE_IDX_LEN = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 3;\nexport const TRIE_NODE_CHILDREN_LEN = TRIE_CHILD_LEN * TRIE_MAX_CHILDREN;\n\nexport const TRIE_NODE_LEN =\n TRIE_NODE_ID_LEN +\n TRIE_NODE_VALUE_ID_LEN +\n TRIE_NODE_VALUE_IDX_LEN +\n TRIE_NODE_CHILDREN_LEN;\n\n// Trie properties\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_LEN = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_LEN = TRIE_NODE_LEN;\n\nexport const TRIE_HEADER_LEN = TRIE_SIZE_LEN + TRIE_ROOT_LEN;\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n MIN_TRIE_SIZE,\n TRIE_CHILD_LEN,\n TRIE_CHILD_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_HEADER_LEN,\n TRIE_ID_IDX,\n TRIE_MAX_CHILDREN,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_CHILDREN_LEN,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_LEN,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NODE_VALUE_ID_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_RED_LEN,\n TRIE_RED_VALUE_IDX_IDX,\n TRIE_RED_ID_IDX,\n} from \"../constants/trie\";\nimport { UTF8_PRINT_OFFSET } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX +\n TRIE_CHILD_LEN * (key[min++] - UTF8_PRINT_OFFSET);\n let child = trie[index + TRIE_CHILD_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_LEN > trie.length) {\n trie = grow(trie, child + TRIE_NODE_LEN);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_LEN;\n // Attach and initialize node\n trie[index + TRIE_CHILD_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array {\n const minSize = TRIE_HEADER_LEN;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (at: number, ai: number, bt: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvt = tries[bt][bi + TRIE_NODE_VALUE_ID_IDX];\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX];\n if (bvt !== TRIE_NULL) {\n // If left value is not null\n const avt = tries[at][ai + TRIE_NODE_VALUE_ID_IDX];\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX];\n if (avt !== TRIE_NULL) {\n mergeFn(avt, avi, bvt, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_ID_IDX] = bvt;\n tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_LEN;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_CHILD_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_RED_LEN > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_RED_LEN);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_RED_LEN;\n // Add new redirect\n tries[at][li + TRIE_RED_ID_IDX] = rt;\n tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n id: number,\n value: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, 0, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childKey, childPtr] = stack[top];\n\n // Check if end of children array\n if (childKey >= TRIE_MAX_CHILDREN) {\n --top;\n continue;\n }\n\n // Update stack top\n ++stack[top][1];\n stack[top][2] += TRIE_CHILD_LEN;\n\n // If just reached node\n if (childKey === 0) {\n // Check if the node has a value\n const nodeIndex = childPtr - TRIE_NODE_CHILDREN_IDX;\n const valueId = tries[trieI][nodeIndex + TRIE_NODE_VALUE_ID_IDX];\n if (valueId !== TRIE_NULL) {\n // Print the node's value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX];\n callbackFn(stream, key, top, valueId, valueIndex);\n }\n }\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX];\n if (childI !== TRIE_NULL) {\n // Resolve child if redirect\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX];\n trieI = childTrieI;\n }\n // Add the child to the stack\n key[top] = childKey + UTF8_PRINT_OFFSET;\n stack[++top] = [trieI, 0, childI + TRIE_NODE_CHILDREN_IDX];\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { ENTRY_MAX_LEN, STATION_NAME_MAX_LEN } from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/trie\";\n\nexport async function run(\n filePath: string,\n outPath: string,\n workerPath: string,\n maxWorkers: number,\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const counts: Uint32Array[] = new Array(maxWorkers + 1);\n const maxes: Int16Array[] = new Array(maxWorkers + 1);\n const mins: Int16Array[] = new Array(maxWorkers + 1);\n const sums: Float64Array[] = new Array(maxWorkers + 1);\n const tries: Int32Array[] = new Array(maxWorkers + 1);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i + 1;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({ end, filePath, id, start } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n const id = res.id;\n counts[id] = res.counts;\n maxes[id] = res.maxes;\n mins[id] = res.mins;\n sums[id] = res.sums;\n tries[id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 2; i <= maxWorkers; ++i) {\n mergeLeft(tries, 1, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n flags: \"a\",\n fd: (outPath.length < 1) ? 1 : undefined,\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 1, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(at: number, ai: number, bt: number, bi: number): void {\n counts[at][ai] += counts[bt][bi];\n maxes[at][ai] = Math.max(maxes[at][ai], maxes[bt][bi]);\n mins[at][ai] = Math.min(mins[at][ai], mins[bt][bi]);\n sums[at][ai] += sums[bt][bi];\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vt: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vt][vi] / counts[vt][vi]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vt][vi] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vt][vi] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport {\n TRIE_NODE_VALUE_ID_IDX,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NULL,\n} from \"./constants/trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n}: WorkerRequest): Promise {\n const counts = new Uint32Array(MAX_STATIONS);\n const maxes = new Int16Array(MAX_STATIONS);\n const mins = new Int16Array(MAX_STATIONS);\n const sums = new Float64Array(MAX_STATIONS);\n\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0), counts, maxes, mins, sums };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = 0;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_ID_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_ID_IDX] = id;\n trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n counts[index] = 1;\n maxes[index] = temp;\n mins[index] = temp;\n sums[index] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n ++counts[index];\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n sums[index] += temp;\n }\n\n return { id, trie, counts, maxes, mins, sums };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n return ++min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import os from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], \"\", workerPath, os.availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [\n res.trie.buffer,\n res.counts.buffer,\n res.maxes.buffer,\n res.mins.buffer,\n res.sums.buffer,\n ]);\n });\n}\n"],"names":["open","at","bt","run","Worker","createWriteStream","createReadStream","isMainThread","fileURLToPath","runMain","parentPort","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/trie.ts","../src/utils/trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n/**\n * The maximum value of a byte for UTF-8 code points of up to 2 bytes.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_2B_MAX = 224;\n\n/**\n * The number of non-printable control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_PRINT_OFFSET = 32;\n\n/**\n * The number of printable byte values for UTF-8 code points of up to 2 bytes.\n */\nexport const UTF8_2B_PRINT_MAX = UTF8_2B_MAX - UTF8_PRINT_OFFSET;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_2B_PRINT_MAX } from \"./utf8\";\n\n// Trie static properties\n\n/**\n * Represents null / undefined.\n */\nexport const TRIE_NULL = 0;\n\n/**\n * The minimum size a trie.\n */\nexport const MIN_TRIE_SIZE = 524288; // 2 MiB\n\n/**\n * The default growth factor for growing the size of a trie.\n */\nexport const TRIE_GROWTH_FACTOR = 1.618; // ~phi\n\n/**\n * All trie properties are represented by 32 bits (4 bytes).\n */\nexport const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT;\n\n/**\n * The maximum number of children of any trie node.\n */\nexport const TRIE_MAX_CHILDREN = UTF8_2B_PRINT_MAX;\n\n// Trie child pointer properties\n\nexport const TRIE_CHILD_IDX_IDX = 0;\nexport const TRIE_CHILD_IDX_LEN = 1;\n\nexport const TRIE_CHILD_LEN = TRIE_CHILD_IDX_LEN;\n\n// Trie redirect pointer properties\n\nexport const TRIE_RED_ID_IDX = 0;\nexport const TRIE_RED_ID_LEN = 1;\n\nexport const TRIE_RED_VALUE_IDX_IDX = 1;\nexport const TRIE_RED_VALUE_IDX_LEN = 1;\n\nexport const TRIE_RED_LEN = TRIE_RED_ID_LEN + TRIE_RED_VALUE_IDX_LEN;\n\n// Trie node properties\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_LEN = 1;\n\nexport const TRIE_NODE_VALUE_IDX_IDX = 1;\nexport const TRIE_NODE_VALUE_IDX_LEN = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = TRIE_CHILD_LEN * TRIE_MAX_CHILDREN;\n\nexport const TRIE_NODE_LEN =\n TRIE_NODE_ID_LEN + TRIE_NODE_VALUE_IDX_LEN + TRIE_NODE_CHILDREN_LEN;\n\n// Trie properties\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_LEN = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_LEN = TRIE_NODE_LEN;\n\nexport const TRIE_HEADER_LEN = TRIE_SIZE_LEN + TRIE_ROOT_LEN;\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n MIN_TRIE_SIZE,\n TRIE_CHILD_LEN,\n TRIE_CHILD_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_HEADER_LEN,\n TRIE_ID_IDX,\n TRIE_MAX_CHILDREN,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_CHILDREN_LEN,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_LEN,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_RED_LEN,\n TRIE_RED_VALUE_IDX_IDX,\n TRIE_RED_ID_IDX,\n} from \"../constants/trie\";\nimport { UTF8_PRINT_OFFSET } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX +\n TRIE_CHILD_LEN * (key[min++] - UTF8_PRINT_OFFSET);\n let child = trie[index + TRIE_CHILD_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_LEN > trie.length) {\n trie = grow(trie, child + TRIE_NODE_LEN);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_LEN;\n // Attach and initialize node\n trie[index + TRIE_CHILD_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array {\n const minSize = TRIE_HEADER_LEN;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n console.log(\"D\");\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_LEN;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_CHILD_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_RED_LEN > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_RED_LEN);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_RED_LEN;\n // Add new redirect\n tries[at][li + TRIE_RED_ID_IDX] = rt;\n tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, 0, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childKey, childPtr] = stack[top];\n\n // Check if end of children array\n if (childKey >= TRIE_MAX_CHILDREN) {\n --top;\n continue;\n }\n\n // Update stack top\n ++stack[top][1];\n stack[top][2] += TRIE_CHILD_LEN;\n\n // If just reached node\n if (childKey === 0) {\n // Check if the node has a value\n const nodeIndex = childPtr - TRIE_NODE_CHILDREN_IDX;\n const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print the node's value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n }\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX];\n if (childI !== TRIE_NULL) {\n // Resolve child if redirect\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX];\n trieI = childTrieI;\n }\n // Add the child to the stack\n key[top] = childKey + UTF8_PRINT_OFFSET;\n stack[++top] = [trieI, 0, childI + TRIE_NODE_CHILDREN_IDX];\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/trie\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const numVals = MAX_STATIONS * maxWorkers + 1;\n let bpe = Uint32Array.BYTES_PER_ELEMENT;\n const counts = new Uint32Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Int16Array.BYTES_PER_ELEMENT;\n const maxes = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n const mins = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Float64Array.BYTES_PER_ELEMENT;\n const sums = new Float64Array(new SharedArrayBuffer(bpe * numVals));\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n counts,\n end,\n filePath,\n id,\n maxes,\n mins,\n start,\n sums,\n } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n tries[res.id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 1; i < maxWorkers; ++i) {\n mergeLeft(tries, 0, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(ai: number, bi: number): void {\n counts[ai] += counts[bi];\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n mins[ai] = Math.min(mins[ai], mins[bi]);\n sums[ai] += sums[bi];\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi] / counts[vi]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX_IDX, TRIE_NULL } from \"./constants/trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: WorkerRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n counts[index] = 1;\n maxes[index] = temp;\n mins[index] = temp;\n sums[index] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n ++counts[index];\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n sums[index] += temp;\n }\n\n return { id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n return ++min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [res.trie.buffer]);\n });\n}\n"],"names":["open","at","bt","run","Worker","createWriteStream","createReadStream","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index 8310ea0..e51941a 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -1,4 +1,4 @@ -import os from 'node:os'; +import { availableParallelism } from 'node:os'; import { fileURLToPath } from 'node:url'; import { Worker, isMainThread, parentPort } from 'node:worker_threads'; import { createWriteStream, createReadStream } from 'node:fs'; @@ -76,13 +76,11 @@ const TRIE_RED_VALUE_IDX_LEN = 1; const TRIE_RED_LEN = TRIE_RED_ID_LEN + TRIE_RED_VALUE_IDX_LEN; const TRIE_NODE_ID_IDX = 0; const TRIE_NODE_ID_LEN = 1; -const TRIE_NODE_VALUE_ID_IDX = 1; -const TRIE_NODE_VALUE_ID_LEN = 1; -const TRIE_NODE_VALUE_IDX_IDX = 2; +const TRIE_NODE_VALUE_IDX_IDX = 1; const TRIE_NODE_VALUE_IDX_LEN = 1; -const TRIE_NODE_CHILDREN_IDX = 3; +const TRIE_NODE_CHILDREN_IDX = 2; const TRIE_NODE_CHILDREN_LEN = TRIE_CHILD_LEN * TRIE_MAX_CHILDREN; -const TRIE_NODE_LEN = TRIE_NODE_ID_LEN + TRIE_NODE_VALUE_ID_LEN + TRIE_NODE_VALUE_IDX_LEN + TRIE_NODE_CHILDREN_LEN; +const TRIE_NODE_LEN = TRIE_NODE_ID_LEN + TRIE_NODE_VALUE_IDX_LEN + TRIE_NODE_CHILDREN_LEN; const TRIE_SIZE_IDX = 0; const TRIE_SIZE_LEN = 1; const TRIE_ROOT_IDX = 1; @@ -116,6 +114,7 @@ function createTrie(id = 0, size = MIN_TRIE_SIZE) { return trie; } function grow(trie, minSize = 0) { + console.log("D"); const length = trie[TRIE_SIZE_IDX]; minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR)); const next = new Int32Array(minSize); @@ -132,15 +131,12 @@ function mergeLeft(tries, at, bt, mergeFn) { const Q = queue.length; for (let q = 0; q < Q; ++q) { let [at2, ai, bt2, bi] = queue[q]; - const bvt = tries[bt2][bi + TRIE_NODE_VALUE_ID_IDX]; const bvi = tries[bt2][bi + TRIE_NODE_VALUE_IDX_IDX]; - if (bvt !== TRIE_NULL) { - const avt = tries[at2][ai + TRIE_NODE_VALUE_ID_IDX]; + if (bvi !== TRIE_NULL) { const avi = tries[at2][ai + TRIE_NODE_VALUE_IDX_IDX]; - if (avt !== TRIE_NULL) { - mergeFn(avt, avi, bvt, bvi); + if (avi !== TRIE_NULL) { + mergeFn(avi, bvi); } else { - tries[at2][ai + TRIE_NODE_VALUE_ID_IDX] = bvt; tries[at2][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi; } } @@ -196,14 +192,13 @@ function print(tries, key, trieIndex, stream, separator = "", callbackFn) { stack[top][2] += TRIE_CHILD_LEN; if (childKey === 0) { const nodeIndex = childPtr - TRIE_NODE_CHILDREN_IDX; - const valueId = tries[trieI][nodeIndex + TRIE_NODE_VALUE_ID_IDX]; - if (valueId !== TRIE_NULL) { + const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX]; + if (valueIndex !== TRIE_NULL) { if (tail) { stream.write(separator); } tail = true; - const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX]; - callbackFn(stream, key, top, valueId, valueIndex); + callbackFn(stream, key, top, valueIndex); } } let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX]; @@ -219,7 +214,7 @@ function print(tries, key, trieIndex, stream, separator = "", callbackFn) { } while (top >= 0); } -async function run$1(filePath, outPath, workerPath, maxWorkers) { +async function run$1(filePath, workerPath, maxWorkers, outPath = "") { maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS); const chunks = await getFileChunks( filePath, @@ -228,11 +223,15 @@ async function run$1(filePath, outPath, workerPath, maxWorkers) { CHUNK_SIZE_MIN ); maxWorkers = chunks.length; - const counts = new Array(maxWorkers + 1); - const maxes = new Array(maxWorkers + 1); - const mins = new Array(maxWorkers + 1); - const sums = new Array(maxWorkers + 1); - const tries = new Array(maxWorkers + 1); + const numVals = MAX_STATIONS * maxWorkers + 1; + let bpe = Uint32Array.BYTES_PER_ELEMENT; + const counts = new Uint32Array(new SharedArrayBuffer(bpe * numVals)); + bpe = Int16Array.BYTES_PER_ELEMENT; + const maxes = new Int16Array(new SharedArrayBuffer(bpe * numVals)); + const mins = new Int16Array(new SharedArrayBuffer(bpe * numVals)); + bpe = Float64Array.BYTES_PER_ELEMENT; + const sums = new Float64Array(new SharedArrayBuffer(bpe * numVals)); + const tries = new Array(maxWorkers); const workers = new Array(maxWorkers); for (let i = 0; i < maxWorkers; ++i) { const worker = new Worker(workerPath); @@ -251,52 +250,56 @@ async function run$1(filePath, outPath, workerPath, maxWorkers) { } const tasks = new Array(maxWorkers); for (let i = 0; i < maxWorkers; ++i) { - const id = i + 1; + const id = i; const worker = workers[i]; const [start, end] = chunks[i]; tasks[i] = new Promise((resolve) => { worker.once("message", resolve); - worker.postMessage({ end, filePath, id, start }); + worker.postMessage({ + counts, + end, + filePath, + id, + maxes, + mins, + start, + sums + }); }); } for await (const res of tasks) { - const id = res.id; - counts[id] = res.counts; - maxes[id] = res.maxes; - mins[id] = res.mins; - sums[id] = res.sums; - tries[id] = res.trie; + tries[res.id] = res.trie; } for (let i = 0; i < maxWorkers; ++i) { await workers[i].terminate(); } - for (let i = 2; i <= maxWorkers; ++i) { - mergeLeft(tries, 1, i, mergeStations); + for (let i = 1; i < maxWorkers; ++i) { + mergeLeft(tries, 0, i, mergeStations); } const out = createWriteStream(outPath, { - flags: "a", fd: outPath.length < 1 ? 1 : void 0, + flags: "a", highWaterMark: HIGH_WATER_MARK_OUT }); const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN); out.write("{"); - print(tries, buffer, 1, out, ", ", printStation); + print(tries, buffer, 0, out, ", ", printStation); out.end("}\n"); - function mergeStations(at, ai, bt, bi) { - counts[at][ai] += counts[bt][bi]; - maxes[at][ai] = Math.max(maxes[at][ai], maxes[bt][bi]); - mins[at][ai] = Math.min(mins[at][ai], mins[bt][bi]); - sums[at][ai] += sums[bt][bi]; + function mergeStations(ai, bi) { + counts[ai] += counts[bi]; + maxes[ai] = Math.max(maxes[ai], maxes[bi]); + mins[ai] = Math.min(mins[ai], mins[bi]); + sums[ai] += sums[bi]; } - function printStation(stream, name, nameLen, vt, vi) { - const avg = Math.round(sums[vt][vi] / counts[vt][vi]); + function printStation(stream, name, nameLen, vi) { + const avg = Math.round(sums[vi] / counts[vi]); stream.write(name.toString("utf8", 0, nameLen)); stream.write("="); - stream.write((mins[vt][vi] / 10).toFixed(1)); + stream.write((mins[vi] / 10).toFixed(1)); stream.write("/"); stream.write((avg / 10).toFixed(1)); stream.write("/"); - stream.write((maxes[vt][vi] / 10).toFixed(1)); + stream.write((maxes[vi] / 10).toFixed(1)); } } @@ -304,17 +307,18 @@ async function run({ end, filePath, id, - start + start, + // Shared memory + counts, + maxes, + mins, + sums }) { - const counts = new Uint32Array(MAX_STATIONS); - const maxes = new Int16Array(MAX_STATIONS); - const mins = new Int16Array(MAX_STATIONS); - const sums = new Float64Array(MAX_STATIONS); if (start >= end) { - return { id, trie: createTrie(id, 0), counts, maxes, mins, sums }; + return { id, trie: createTrie(id, 0) }; } let trie = createTrie(id); - let stations = 0; + let stations = id * MAX_STATIONS + 1; const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN); const stream = createReadStream(filePath, { start, @@ -335,10 +339,9 @@ async function run({ const tempV = parseDouble(buffer, tempI, bufI); bufI = 0; [trie, leaf] = add(trie, buffer, 0, tempI); - if (trie[leaf + TRIE_NODE_VALUE_ID_IDX] !== TRIE_NULL) { + if (trie[leaf + TRIE_NODE_VALUE_IDX_IDX] !== TRIE_NULL) { updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV); } else { - trie[leaf + TRIE_NODE_VALUE_ID_IDX] = id; trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations; newStation(stations++, tempV); } @@ -357,7 +360,7 @@ async function run({ mins[index] = mins[index] <= temp ? mins[index] : temp; sums[index] += temp; } - return { id, trie, counts, maxes, mins, sums }; + return { id, trie }; } function parseDouble(b, min, max) { if (b[min] === CHAR_MINUS) { @@ -368,17 +371,11 @@ function parseDouble(b, min, max) { if (isMainThread) { const workerPath = fileURLToPath(import.meta.url); - run$1(process.argv[2], "", workerPath, os.availableParallelism()); + run$1(process.argv[2], workerPath, availableParallelism()); } else { parentPort.addListener("message", async (req) => { const res = await run(req); - parentPort.postMessage(res, [ - res.trie.buffer, - res.counts.buffer, - res.maxes.buffer, - res.mins.buffer, - res.sums.buffer - ]); + parentPort.postMessage(res, [res.trie.buffer]); }); } //# sourceMappingURL=index.mjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index bbbf5db..a86b9cb 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1 +1 @@ -{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/trie.ts","../src/utils/trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n/**\n * The maximum value of a byte for UTF-8 code points of up to 2 bytes.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_2B_MAX = 224;\n\n/**\n * The number of non-printable control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_PRINT_OFFSET = 32;\n\n/**\n * The number of printable byte values for UTF-8 code points of up to 2 bytes.\n */\nexport const UTF8_2B_PRINT_MAX = UTF8_2B_MAX - UTF8_PRINT_OFFSET;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_2B_PRINT_MAX } from \"./utf8\";\n\n// Trie static properties\n\n/**\n * Represents null / undefined.\n */\nexport const TRIE_NULL = 0;\n\n/**\n * The minimum size a trie.\n */\nexport const MIN_TRIE_SIZE = 524288; // 2 MiB\n\n/**\n * The default growth factor for growing the size of a trie.\n */\nexport const TRIE_GROWTH_FACTOR = 1.618; // ~phi\n\n/**\n * All trie properties are represented by 32 bits (4 bytes).\n */\nexport const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT;\n\n/**\n * The maximum number of children of any trie node.\n */\nexport const TRIE_MAX_CHILDREN = UTF8_2B_PRINT_MAX;\n\n// Trie child pointer properties\n\nexport const TRIE_CHILD_IDX_IDX = 0;\nexport const TRIE_CHILD_IDX_LEN = 1;\n\nexport const TRIE_CHILD_LEN = TRIE_CHILD_IDX_LEN;\n\n// Trie redirect pointer properties\n\nexport const TRIE_RED_ID_IDX = 0;\nexport const TRIE_RED_ID_LEN = 1;\n\nexport const TRIE_RED_VALUE_IDX_IDX = 1;\nexport const TRIE_RED_VALUE_IDX_LEN = 1;\n\nexport const TRIE_RED_LEN = TRIE_RED_ID_LEN + TRIE_RED_VALUE_IDX_LEN;\n\n// Trie node properties\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_LEN = 1;\n\nexport const TRIE_NODE_VALUE_ID_IDX = 1;\nexport const TRIE_NODE_VALUE_ID_LEN = 1;\n\nexport const TRIE_NODE_VALUE_IDX_IDX = 2;\nexport const TRIE_NODE_VALUE_IDX_LEN = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 3;\nexport const TRIE_NODE_CHILDREN_LEN = TRIE_CHILD_LEN * TRIE_MAX_CHILDREN;\n\nexport const TRIE_NODE_LEN =\n TRIE_NODE_ID_LEN +\n TRIE_NODE_VALUE_ID_LEN +\n TRIE_NODE_VALUE_IDX_LEN +\n TRIE_NODE_CHILDREN_LEN;\n\n// Trie properties\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_LEN = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_LEN = TRIE_NODE_LEN;\n\nexport const TRIE_HEADER_LEN = TRIE_SIZE_LEN + TRIE_ROOT_LEN;\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n MIN_TRIE_SIZE,\n TRIE_CHILD_LEN,\n TRIE_CHILD_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_HEADER_LEN,\n TRIE_ID_IDX,\n TRIE_MAX_CHILDREN,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_CHILDREN_LEN,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_LEN,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NODE_VALUE_ID_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_RED_LEN,\n TRIE_RED_VALUE_IDX_IDX,\n TRIE_RED_ID_IDX,\n} from \"../constants/trie\";\nimport { UTF8_PRINT_OFFSET } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX +\n TRIE_CHILD_LEN * (key[min++] - UTF8_PRINT_OFFSET);\n let child = trie[index + TRIE_CHILD_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_LEN > trie.length) {\n trie = grow(trie, child + TRIE_NODE_LEN);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_LEN;\n // Attach and initialize node\n trie[index + TRIE_CHILD_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array {\n const minSize = TRIE_HEADER_LEN;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (at: number, ai: number, bt: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvt = tries[bt][bi + TRIE_NODE_VALUE_ID_IDX];\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX];\n if (bvt !== TRIE_NULL) {\n // If left value is not null\n const avt = tries[at][ai + TRIE_NODE_VALUE_ID_IDX];\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX];\n if (avt !== TRIE_NULL) {\n mergeFn(avt, avi, bvt, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_ID_IDX] = bvt;\n tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_LEN;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_CHILD_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_RED_LEN > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_RED_LEN);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_RED_LEN;\n // Add new redirect\n tries[at][li + TRIE_RED_ID_IDX] = rt;\n tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n id: number,\n value: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, 0, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childKey, childPtr] = stack[top];\n\n // Check if end of children array\n if (childKey >= TRIE_MAX_CHILDREN) {\n --top;\n continue;\n }\n\n // Update stack top\n ++stack[top][1];\n stack[top][2] += TRIE_CHILD_LEN;\n\n // If just reached node\n if (childKey === 0) {\n // Check if the node has a value\n const nodeIndex = childPtr - TRIE_NODE_CHILDREN_IDX;\n const valueId = tries[trieI][nodeIndex + TRIE_NODE_VALUE_ID_IDX];\n if (valueId !== TRIE_NULL) {\n // Print the node's value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX];\n callbackFn(stream, key, top, valueId, valueIndex);\n }\n }\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX];\n if (childI !== TRIE_NULL) {\n // Resolve child if redirect\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX];\n trieI = childTrieI;\n }\n // Add the child to the stack\n key[top] = childKey + UTF8_PRINT_OFFSET;\n stack[++top] = [trieI, 0, childI + TRIE_NODE_CHILDREN_IDX];\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { ENTRY_MAX_LEN, STATION_NAME_MAX_LEN } from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/trie\";\n\nexport async function run(\n filePath: string,\n outPath: string,\n workerPath: string,\n maxWorkers: number,\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const counts: Uint32Array[] = new Array(maxWorkers + 1);\n const maxes: Int16Array[] = new Array(maxWorkers + 1);\n const mins: Int16Array[] = new Array(maxWorkers + 1);\n const sums: Float64Array[] = new Array(maxWorkers + 1);\n const tries: Int32Array[] = new Array(maxWorkers + 1);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i + 1;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({ end, filePath, id, start } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n const id = res.id;\n counts[id] = res.counts;\n maxes[id] = res.maxes;\n mins[id] = res.mins;\n sums[id] = res.sums;\n tries[id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 2; i <= maxWorkers; ++i) {\n mergeLeft(tries, 1, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n flags: \"a\",\n fd: (outPath.length < 1) ? 1 : undefined,\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 1, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(at: number, ai: number, bt: number, bi: number): void {\n counts[at][ai] += counts[bt][bi];\n maxes[at][ai] = Math.max(maxes[at][ai], maxes[bt][bi]);\n mins[at][ai] = Math.min(mins[at][ai], mins[bt][bi]);\n sums[at][ai] += sums[bt][bi];\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vt: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vt][vi] / counts[vt][vi]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vt][vi] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vt][vi] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport {\n TRIE_NODE_VALUE_ID_IDX,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NULL,\n} from \"./constants/trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n}: WorkerRequest): Promise {\n const counts = new Uint32Array(MAX_STATIONS);\n const maxes = new Int16Array(MAX_STATIONS);\n const mins = new Int16Array(MAX_STATIONS);\n const sums = new Float64Array(MAX_STATIONS);\n\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0), counts, maxes, mins, sums };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = 0;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_ID_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_ID_IDX] = id;\n trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n counts[index] = 1;\n maxes[index] = temp;\n mins[index] = temp;\n sums[index] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n ++counts[index];\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n sums[index] += temp;\n }\n\n return { id, trie, counts, maxes, mins, sums };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n return ++min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import os from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], \"\", workerPath, os.availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [\n res.trie.buffer,\n res.counts.buffer,\n res.maxes.buffer,\n res.mins.buffer,\n res.sums.buffer,\n ]);\n });\n}\n"],"names":["at","bt","run","runMain","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/trie.ts","../src/utils/trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n/**\n * The maximum value of a byte for UTF-8 code points of up to 2 bytes.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_2B_MAX = 224;\n\n/**\n * The number of non-printable control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_PRINT_OFFSET = 32;\n\n/**\n * The number of printable byte values for UTF-8 code points of up to 2 bytes.\n */\nexport const UTF8_2B_PRINT_MAX = UTF8_2B_MAX - UTF8_PRINT_OFFSET;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_2B_PRINT_MAX } from \"./utf8\";\n\n// Trie static properties\n\n/**\n * Represents null / undefined.\n */\nexport const TRIE_NULL = 0;\n\n/**\n * The minimum size a trie.\n */\nexport const MIN_TRIE_SIZE = 524288; // 2 MiB\n\n/**\n * The default growth factor for growing the size of a trie.\n */\nexport const TRIE_GROWTH_FACTOR = 1.618; // ~phi\n\n/**\n * All trie properties are represented by 32 bits (4 bytes).\n */\nexport const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT;\n\n/**\n * The maximum number of children of any trie node.\n */\nexport const TRIE_MAX_CHILDREN = UTF8_2B_PRINT_MAX;\n\n// Trie child pointer properties\n\nexport const TRIE_CHILD_IDX_IDX = 0;\nexport const TRIE_CHILD_IDX_LEN = 1;\n\nexport const TRIE_CHILD_LEN = TRIE_CHILD_IDX_LEN;\n\n// Trie redirect pointer properties\n\nexport const TRIE_RED_ID_IDX = 0;\nexport const TRIE_RED_ID_LEN = 1;\n\nexport const TRIE_RED_VALUE_IDX_IDX = 1;\nexport const TRIE_RED_VALUE_IDX_LEN = 1;\n\nexport const TRIE_RED_LEN = TRIE_RED_ID_LEN + TRIE_RED_VALUE_IDX_LEN;\n\n// Trie node properties\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_LEN = 1;\n\nexport const TRIE_NODE_VALUE_IDX_IDX = 1;\nexport const TRIE_NODE_VALUE_IDX_LEN = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = TRIE_CHILD_LEN * TRIE_MAX_CHILDREN;\n\nexport const TRIE_NODE_LEN =\n TRIE_NODE_ID_LEN + TRIE_NODE_VALUE_IDX_LEN + TRIE_NODE_CHILDREN_LEN;\n\n// Trie properties\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_LEN = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_LEN = TRIE_NODE_LEN;\n\nexport const TRIE_HEADER_LEN = TRIE_SIZE_LEN + TRIE_ROOT_LEN;\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n MIN_TRIE_SIZE,\n TRIE_CHILD_LEN,\n TRIE_CHILD_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_HEADER_LEN,\n TRIE_ID_IDX,\n TRIE_MAX_CHILDREN,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_CHILDREN_LEN,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_LEN,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_RED_LEN,\n TRIE_RED_VALUE_IDX_IDX,\n TRIE_RED_ID_IDX,\n} from \"../constants/trie\";\nimport { UTF8_PRINT_OFFSET } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX +\n TRIE_CHILD_LEN * (key[min++] - UTF8_PRINT_OFFSET);\n let child = trie[index + TRIE_CHILD_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_LEN > trie.length) {\n trie = grow(trie, child + TRIE_NODE_LEN);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_LEN;\n // Attach and initialize node\n trie[index + TRIE_CHILD_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array {\n const minSize = TRIE_HEADER_LEN;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n console.log(\"D\");\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_LEN;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_CHILD_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_RED_LEN > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_RED_LEN);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_RED_LEN;\n // Add new redirect\n tries[at][li + TRIE_RED_ID_IDX] = rt;\n tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, 0, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childKey, childPtr] = stack[top];\n\n // Check if end of children array\n if (childKey >= TRIE_MAX_CHILDREN) {\n --top;\n continue;\n }\n\n // Update stack top\n ++stack[top][1];\n stack[top][2] += TRIE_CHILD_LEN;\n\n // If just reached node\n if (childKey === 0) {\n // Check if the node has a value\n const nodeIndex = childPtr - TRIE_NODE_CHILDREN_IDX;\n const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print the node's value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n }\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX];\n if (childI !== TRIE_NULL) {\n // Resolve child if redirect\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX];\n trieI = childTrieI;\n }\n // Add the child to the stack\n key[top] = childKey + UTF8_PRINT_OFFSET;\n stack[++top] = [trieI, 0, childI + TRIE_NODE_CHILDREN_IDX];\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/trie\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const numVals = MAX_STATIONS * maxWorkers + 1;\n let bpe = Uint32Array.BYTES_PER_ELEMENT;\n const counts = new Uint32Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Int16Array.BYTES_PER_ELEMENT;\n const maxes = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n const mins = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Float64Array.BYTES_PER_ELEMENT;\n const sums = new Float64Array(new SharedArrayBuffer(bpe * numVals));\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n counts,\n end,\n filePath,\n id,\n maxes,\n mins,\n start,\n sums,\n } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n tries[res.id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 1; i < maxWorkers; ++i) {\n mergeLeft(tries, 0, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(ai: number, bi: number): void {\n counts[ai] += counts[bi];\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n mins[ai] = Math.min(mins[ai], mins[bi]);\n sums[ai] += sums[bi];\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi] / counts[vi]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX_IDX, TRIE_NULL } from \"./constants/trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: WorkerRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n counts[index] = 1;\n maxes[index] = temp;\n mins[index] = temp;\n sums[index] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n ++counts[index];\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n sums[index] += temp;\n }\n\n return { id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n return ++min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [res.trie.buffer]);\n });\n}\n"],"names":["at","bt","run","runMain","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/src/constants/trie.ts b/src/main/nodejs/havelessbemore/src/constants/trie.ts index 0e3c436..a786190 100644 --- a/src/main/nodejs/havelessbemore/src/constants/trie.ts +++ b/src/main/nodejs/havelessbemore/src/constants/trie.ts @@ -49,20 +49,14 @@ export const TRIE_RED_LEN = TRIE_RED_ID_LEN + TRIE_RED_VALUE_IDX_LEN; export const TRIE_NODE_ID_IDX = 0; export const TRIE_NODE_ID_LEN = 1; -export const TRIE_NODE_VALUE_ID_IDX = 1; -export const TRIE_NODE_VALUE_ID_LEN = 1; - -export const TRIE_NODE_VALUE_IDX_IDX = 2; +export const TRIE_NODE_VALUE_IDX_IDX = 1; export const TRIE_NODE_VALUE_IDX_LEN = 1; -export const TRIE_NODE_CHILDREN_IDX = 3; +export const TRIE_NODE_CHILDREN_IDX = 2; export const TRIE_NODE_CHILDREN_LEN = TRIE_CHILD_LEN * TRIE_MAX_CHILDREN; export const TRIE_NODE_LEN = - TRIE_NODE_ID_LEN + - TRIE_NODE_VALUE_ID_LEN + - TRIE_NODE_VALUE_IDX_LEN + - TRIE_NODE_CHILDREN_LEN; + TRIE_NODE_ID_LEN + TRIE_NODE_VALUE_IDX_LEN + TRIE_NODE_CHILDREN_LEN; // Trie properties diff --git a/src/main/nodejs/havelessbemore/src/index.ts b/src/main/nodejs/havelessbemore/src/index.ts index 4a2c785..4f159cc 100644 --- a/src/main/nodejs/havelessbemore/src/index.ts +++ b/src/main/nodejs/havelessbemore/src/index.ts @@ -13,12 +13,6 @@ if (isMainThread) { } else { parentPort!.addListener("message", async (req: WorkerRequest) => { const res = await runWorker(req); - parentPort!.postMessage(res, [ - res.trie.buffer, - res.counts.buffer, - res.maxes.buffer, - res.mins.buffer, - res.sums.buffer, - ]); + parentPort!.postMessage(res, [res.trie.buffer]); }); } diff --git a/src/main/nodejs/havelessbemore/src/main.ts b/src/main/nodejs/havelessbemore/src/main.ts index 7be98df..1fa9848 100644 --- a/src/main/nodejs/havelessbemore/src/main.ts +++ b/src/main/nodejs/havelessbemore/src/main.ts @@ -4,7 +4,11 @@ import { Worker } from "node:worker_threads"; import type { WorkerRequest } from "./types/workerRequest"; import type { WorkerResponse } from "./types/workerResponse"; -import { ENTRY_MAX_LEN, STATION_NAME_MAX_LEN } from "./constants/constraints"; +import { + ENTRY_MAX_LEN, + MAX_STATIONS, + STATION_NAME_MAX_LEN, +} from "./constants/constraints"; import { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from "./constants/stream"; import { MAX_WORKERS, MIN_WORKERS } from "./constants/workers"; import { clamp, getFileChunks } from "./utils/stream"; @@ -14,7 +18,7 @@ export async function run( filePath: string, workerPath: string, maxWorkers: number, - outPath = "" + outPath = "", ): Promise { // Sanitize number of workers maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS); @@ -31,11 +35,15 @@ export async function run( maxWorkers = chunks.length; // Initialize data - const counts: Uint32Array[] = new Array(maxWorkers + 1); - const maxes: Int16Array[] = new Array(maxWorkers + 1); - const mins: Int16Array[] = new Array(maxWorkers + 1); - const sums: Float64Array[] = new Array(maxWorkers + 1); - const tries: Int32Array[] = new Array(maxWorkers + 1); + const numVals = MAX_STATIONS * maxWorkers + 1; + let bpe = Uint32Array.BYTES_PER_ELEMENT; + const counts = new Uint32Array(new SharedArrayBuffer(bpe * numVals)); + bpe = Int16Array.BYTES_PER_ELEMENT; + const maxes = new Int16Array(new SharedArrayBuffer(bpe * numVals)); + const mins = new Int16Array(new SharedArrayBuffer(bpe * numVals)); + bpe = Float64Array.BYTES_PER_ELEMENT; + const sums = new Float64Array(new SharedArrayBuffer(bpe * numVals)); + const tries: Int32Array[] = new Array(maxWorkers); // Create workers const workers = new Array(maxWorkers); @@ -58,23 +66,27 @@ export async function run( // Process each chunk const tasks = new Array>(maxWorkers); for (let i = 0; i < maxWorkers; ++i) { - const id = i + 1; + const id = i; const worker = workers[i]; const [start, end] = chunks[i]; tasks[i] = new Promise((resolve) => { worker.once("message", resolve); - worker.postMessage({ end, filePath, id, start } as WorkerRequest); + worker.postMessage({ + counts, + end, + filePath, + id, + maxes, + mins, + start, + sums, + } as WorkerRequest); }); } // Wait for completion for await (const res of tasks) { - const id = res.id; - counts[id] = res.counts; - maxes[id] = res.maxes; - mins[id] = res.mins; - sums[id] = res.sums; - tries[id] = res.trie; + tries[res.id] = res.trie; } // Terminate workers @@ -83,42 +95,41 @@ export async function run( } // Merge tries - for (let i = 2; i <= maxWorkers; ++i) { - mergeLeft(tries, 1, i, mergeStations); + for (let i = 1; i < maxWorkers; ++i) { + mergeLeft(tries, 0, i, mergeStations); } // Print results const out = createWriteStream(outPath, { - fd: (outPath.length < 1) ? 1 : undefined, + fd: outPath.length < 1 ? 1 : undefined, flags: "a", highWaterMark: HIGH_WATER_MARK_OUT, }); const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN); out.write("{"); - print(tries, buffer, 1, out, ", ", printStation); + print(tries, buffer, 0, out, ", ", printStation); out.end("}\n"); - function mergeStations(at: number, ai: number, bt: number, bi: number): void { - counts[at][ai] += counts[bt][bi]; - maxes[at][ai] = Math.max(maxes[at][ai], maxes[bt][bi]); - mins[at][ai] = Math.min(mins[at][ai], mins[bt][bi]); - sums[at][ai] += sums[bt][bi]; + function mergeStations(ai: number, bi: number): void { + counts[ai] += counts[bi]; + maxes[ai] = Math.max(maxes[ai], maxes[bi]); + mins[ai] = Math.min(mins[ai], mins[bi]); + sums[ai] += sums[bi]; } function printStation( stream: WriteStream, name: Buffer, nameLen: number, - vt: number, vi: number, ): void { - const avg = Math.round(sums[vt][vi] / counts[vt][vi]); + const avg = Math.round(sums[vi] / counts[vi]); stream.write(name.toString("utf8", 0, nameLen)); stream.write("="); - stream.write((mins[vt][vi] / 10).toFixed(1)); + stream.write((mins[vi] / 10).toFixed(1)); stream.write("/"); stream.write((avg / 10).toFixed(1)); stream.write("/"); - stream.write((maxes[vt][vi] / 10).toFixed(1)); + stream.write((maxes[vi] / 10).toFixed(1)); } } diff --git a/src/main/nodejs/havelessbemore/src/types/workerRequest.ts b/src/main/nodejs/havelessbemore/src/types/workerRequest.ts index 72202f9..88909f9 100644 --- a/src/main/nodejs/havelessbemore/src/types/workerRequest.ts +++ b/src/main/nodejs/havelessbemore/src/types/workerRequest.ts @@ -3,4 +3,9 @@ export interface WorkerRequest { filePath: string; id: number; start: number; + // Shared memory + counts: Uint32Array; + maxes: Int16Array; + mins: Int16Array; + sums: Float64Array; } diff --git a/src/main/nodejs/havelessbemore/src/types/workerResponse.ts b/src/main/nodejs/havelessbemore/src/types/workerResponse.ts index 155ec56..42f8c1f 100644 --- a/src/main/nodejs/havelessbemore/src/types/workerResponse.ts +++ b/src/main/nodejs/havelessbemore/src/types/workerResponse.ts @@ -1,8 +1,4 @@ export interface WorkerResponse { - counts: Uint32Array; id: number; - maxes: Int16Array; - mins: Int16Array; - sums: Float64Array; trie: Int32Array; } diff --git a/src/main/nodejs/havelessbemore/src/utils/trie.ts b/src/main/nodejs/havelessbemore/src/utils/trie.ts index b90d260..2ef1c54 100644 --- a/src/main/nodejs/havelessbemore/src/utils/trie.ts +++ b/src/main/nodejs/havelessbemore/src/utils/trie.ts @@ -13,7 +13,6 @@ import { TRIE_NODE_ID_IDX, TRIE_NODE_LEN, TRIE_NODE_VALUE_IDX_IDX, - TRIE_NODE_VALUE_ID_IDX, TRIE_NULL, TRIE_ROOT_IDX, TRIE_SIZE_IDX, @@ -61,6 +60,7 @@ export function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array { } export function grow(trie: Int32Array, minSize = 0): Int32Array { + console.log("D"); const length = trie[TRIE_SIZE_IDX]; minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR)); const next = new Int32Array(minSize); @@ -74,7 +74,7 @@ export function mergeLeft( tries: Int32Array[], at: number, bt: number, - mergeFn: (at: number, ai: number, bt: number, bi: number) => void, + mergeFn: (ai: number, bi: number) => void, ): void { const queue: [number, number, number, number][] = [ [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX], @@ -86,16 +86,13 @@ export function mergeLeft( let [at, ai, bt, bi] = queue[q]; // If right value is not null - const bvt = tries[bt][bi + TRIE_NODE_VALUE_ID_IDX]; const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX]; - if (bvt !== TRIE_NULL) { + if (bvi !== TRIE_NULL) { // If left value is not null - const avt = tries[at][ai + TRIE_NODE_VALUE_ID_IDX]; const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX]; - if (avt !== TRIE_NULL) { - mergeFn(avt, avi, bvt, bvi); + if (avi !== TRIE_NULL) { + mergeFn(avi, bvi); } else { - tries[at][ai + TRIE_NODE_VALUE_ID_IDX] = bvt; tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi; } } @@ -163,8 +160,7 @@ export function print( stream: WriteStream, key: Buffer, keyLen: number, - id: number, - value: number, + valueIndex: number, ) => void, ): void { const stack: [number, number, number][] = new Array(key.length + 1); @@ -189,15 +185,14 @@ export function print( if (childKey === 0) { // Check if the node has a value const nodeIndex = childPtr - TRIE_NODE_CHILDREN_IDX; - const valueId = tries[trieI][nodeIndex + TRIE_NODE_VALUE_ID_IDX]; - if (valueId !== TRIE_NULL) { + const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX]; + if (valueIndex !== TRIE_NULL) { // Print the node's value if (tail) { stream.write(separator); } tail = true; - const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX]; - callbackFn(stream, key, top, valueId, valueIndex); + callbackFn(stream, key, top, valueIndex); } } diff --git a/src/main/nodejs/havelessbemore/src/worker.ts b/src/main/nodejs/havelessbemore/src/worker.ts index ff73c4d..37b1016 100644 --- a/src/main/nodejs/havelessbemore/src/worker.ts +++ b/src/main/nodejs/havelessbemore/src/worker.ts @@ -8,11 +8,7 @@ import { CHAR_NEWLINE } from "./constants/utf8"; import { CHAR_MINUS } from "./constants/utf8"; import { ENTRY_MAX_LEN, MAX_STATIONS } from "./constants/constraints"; import { CHAR_ZERO_11, CHAR_ZERO_111 } from "./constants/stream"; -import { - TRIE_NODE_VALUE_ID_IDX, - TRIE_NODE_VALUE_IDX_IDX, - TRIE_NULL, -} from "./constants/trie"; +import { TRIE_NODE_VALUE_IDX_IDX, TRIE_NULL } from "./constants/trie"; import { getHighWaterMark } from "./utils/stream"; import { add, createTrie } from "./utils/trie"; @@ -21,20 +17,20 @@ export async function run({ filePath, id, start, + // Shared memory + counts, + maxes, + mins, + sums, }: WorkerRequest): Promise { - const counts = new Uint32Array(MAX_STATIONS); - const maxes = new Int16Array(MAX_STATIONS); - const mins = new Int16Array(MAX_STATIONS); - const sums = new Float64Array(MAX_STATIONS); - // Check chunk size if (start >= end) { - return { id, trie: createTrie(id, 0), counts, maxes, mins, sums }; + return { id, trie: createTrie(id, 0) }; } // Initialize constants let trie = createTrie(id); - let stations = 0; + let stations = id * MAX_STATIONS + 1; const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN); // Create the chunk stream @@ -65,12 +61,11 @@ export async function run({ // Add the station's name to the trie and get leaf index [trie, leaf] = add(trie, buffer, 0, tempI); // If the station existed - if (trie[leaf + TRIE_NODE_VALUE_ID_IDX] !== TRIE_NULL) { + if (trie[leaf + TRIE_NODE_VALUE_IDX_IDX] !== TRIE_NULL) { // Update the station's value updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV); } else { // Add the new station's value - trie[leaf + TRIE_NODE_VALUE_ID_IDX] = id; trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations; newStation(stations++, tempV); } @@ -92,7 +87,7 @@ export async function run({ sums[index] += temp; } - return { id, trie, counts, maxes, mins, sums }; + return { id, trie }; } export function parseDouble(b: Buffer, min: number, max: number): number { From e511efe5d09863697d367db72dc51e854c043e2d Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Wed, 22 May 2024 11:33:58 -0400 Subject: [PATCH 05/69] Rename trie to utf8Trie --- src/main/nodejs/havelessbemore/README.md | 4 +- src/main/nodejs/havelessbemore/dist/index.cjs | 12 ++--- .../nodejs/havelessbemore/dist/index.cjs.map | 2 +- src/main/nodejs/havelessbemore/dist/index.mjs | 12 ++--- .../nodejs/havelessbemore/dist/index.mjs.map | 2 +- .../havelessbemore/src/constants/utf8.ts | 47 ++++++++++++++++--- .../src/constants/{trie.ts => utf8Trie.ts} | 6 +-- src/main/nodejs/havelessbemore/src/main.ts | 2 +- .../src/utils/{trie.ts => utf8Trie.ts} | 9 ++-- src/main/nodejs/havelessbemore/src/worker.ts | 4 +- 10 files changed, 66 insertions(+), 34 deletions(-) rename src/main/nodejs/havelessbemore/src/constants/{trie.ts => utf8Trie.ts} (94%) rename src/main/nodejs/havelessbemore/src/utils/{trie.ts => utf8Trie.ts} (96%) diff --git a/src/main/nodejs/havelessbemore/README.md b/src/main/nodejs/havelessbemore/README.md index 5ef3550..28697c5 100644 --- a/src/main/nodejs/havelessbemore/README.md +++ b/src/main/nodejs/havelessbemore/README.md @@ -14,8 +14,8 @@ ### Results -- Best: 14.8s -- Avg: 15-16s +- Min: 14.8s +- Avg: 15.5s ### Specs: diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs b/src/main/nodejs/havelessbemore/dist/index.cjs index 69efdc5..b48e322 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs +++ b/src/main/nodejs/havelessbemore/dist/index.cjs @@ -15,9 +15,9 @@ const CHAR_MINUS = 45; const CHAR_NEWLINE = 10; const CHAR_SEMICOLON = 59; const CHAR_ZERO = 48; -const UTF8_2B_MAX = 224; -const UTF8_PRINT_OFFSET = 32; -const UTF8_2B_PRINT_MAX = UTF8_2B_MAX - UTF8_PRINT_OFFSET; +const UTF8_B0_MIN = 32; +const UTF8_B0_2B_MAX = 223; +const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1; const HIGH_WATER_MARK_MIN = 16384; const HIGH_WATER_MARK_MAX = 1048576; @@ -68,7 +68,7 @@ function getHighWaterMark(size) { const TRIE_NULL = 0; const MIN_TRIE_SIZE = 524288; const TRIE_GROWTH_FACTOR = 1.618; -const TRIE_MAX_CHILDREN = UTF8_2B_PRINT_MAX; +const TRIE_MAX_CHILDREN = UTF8_B0_2B_LEN; const TRIE_CHILD_IDX_IDX = 0; const TRIE_CHILD_IDX_LEN = 1; const TRIE_CHILD_LEN = TRIE_CHILD_IDX_LEN; @@ -94,7 +94,7 @@ const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX; function add(trie, key, min, max) { let index = TRIE_ROOT_IDX; while (min < max) { - index += TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_LEN * (key[min++] - UTF8_PRINT_OFFSET); + index += TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_LEN * (key[min++] - UTF8_B0_MIN); let child = trie[index + TRIE_CHILD_IDX_IDX]; if (child === TRIE_NULL) { child = trie[TRIE_SIZE_IDX]; @@ -211,7 +211,7 @@ function print(tries, key, trieIndex, stream, separator = "", callbackFn) { childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX]; trieI = childTrieI; } - key[top] = childKey + UTF8_PRINT_OFFSET; + key[top] = childKey + UTF8_B0_MIN; stack[++top] = [trieI, 0, childI + TRIE_NODE_CHILDREN_IDX]; } } while (top >= 0); diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs.map b/src/main/nodejs/havelessbemore/dist/index.cjs.map index 18c267c..f70b3e7 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.cjs.map @@ -1 +1 @@ -{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/trie.ts","../src/utils/trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n/**\n * The maximum value of a byte for UTF-8 code points of up to 2 bytes.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_2B_MAX = 224;\n\n/**\n * The number of non-printable control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_PRINT_OFFSET = 32;\n\n/**\n * The number of printable byte values for UTF-8 code points of up to 2 bytes.\n */\nexport const UTF8_2B_PRINT_MAX = UTF8_2B_MAX - UTF8_PRINT_OFFSET;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_2B_PRINT_MAX } from \"./utf8\";\n\n// Trie static properties\n\n/**\n * Represents null / undefined.\n */\nexport const TRIE_NULL = 0;\n\n/**\n * The minimum size a trie.\n */\nexport const MIN_TRIE_SIZE = 524288; // 2 MiB\n\n/**\n * The default growth factor for growing the size of a trie.\n */\nexport const TRIE_GROWTH_FACTOR = 1.618; // ~phi\n\n/**\n * All trie properties are represented by 32 bits (4 bytes).\n */\nexport const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT;\n\n/**\n * The maximum number of children of any trie node.\n */\nexport const TRIE_MAX_CHILDREN = UTF8_2B_PRINT_MAX;\n\n// Trie child pointer properties\n\nexport const TRIE_CHILD_IDX_IDX = 0;\nexport const TRIE_CHILD_IDX_LEN = 1;\n\nexport const TRIE_CHILD_LEN = TRIE_CHILD_IDX_LEN;\n\n// Trie redirect pointer properties\n\nexport const TRIE_RED_ID_IDX = 0;\nexport const TRIE_RED_ID_LEN = 1;\n\nexport const TRIE_RED_VALUE_IDX_IDX = 1;\nexport const TRIE_RED_VALUE_IDX_LEN = 1;\n\nexport const TRIE_RED_LEN = TRIE_RED_ID_LEN + TRIE_RED_VALUE_IDX_LEN;\n\n// Trie node properties\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_LEN = 1;\n\nexport const TRIE_NODE_VALUE_IDX_IDX = 1;\nexport const TRIE_NODE_VALUE_IDX_LEN = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = TRIE_CHILD_LEN * TRIE_MAX_CHILDREN;\n\nexport const TRIE_NODE_LEN =\n TRIE_NODE_ID_LEN + TRIE_NODE_VALUE_IDX_LEN + TRIE_NODE_CHILDREN_LEN;\n\n// Trie properties\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_LEN = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_LEN = TRIE_NODE_LEN;\n\nexport const TRIE_HEADER_LEN = TRIE_SIZE_LEN + TRIE_ROOT_LEN;\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n MIN_TRIE_SIZE,\n TRIE_CHILD_LEN,\n TRIE_CHILD_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_HEADER_LEN,\n TRIE_ID_IDX,\n TRIE_MAX_CHILDREN,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_CHILDREN_LEN,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_LEN,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_RED_LEN,\n TRIE_RED_VALUE_IDX_IDX,\n TRIE_RED_ID_IDX,\n} from \"../constants/trie\";\nimport { UTF8_PRINT_OFFSET } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX +\n TRIE_CHILD_LEN * (key[min++] - UTF8_PRINT_OFFSET);\n let child = trie[index + TRIE_CHILD_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_LEN > trie.length) {\n trie = grow(trie, child + TRIE_NODE_LEN);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_LEN;\n // Attach and initialize node\n trie[index + TRIE_CHILD_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array {\n const minSize = TRIE_HEADER_LEN;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n console.log(\"D\");\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_LEN;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_CHILD_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_RED_LEN > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_RED_LEN);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_RED_LEN;\n // Add new redirect\n tries[at][li + TRIE_RED_ID_IDX] = rt;\n tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, 0, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childKey, childPtr] = stack[top];\n\n // Check if end of children array\n if (childKey >= TRIE_MAX_CHILDREN) {\n --top;\n continue;\n }\n\n // Update stack top\n ++stack[top][1];\n stack[top][2] += TRIE_CHILD_LEN;\n\n // If just reached node\n if (childKey === 0) {\n // Check if the node has a value\n const nodeIndex = childPtr - TRIE_NODE_CHILDREN_IDX;\n const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print the node's value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n }\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX];\n if (childI !== TRIE_NULL) {\n // Resolve child if redirect\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX];\n trieI = childTrieI;\n }\n // Add the child to the stack\n key[top] = childKey + UTF8_PRINT_OFFSET;\n stack[++top] = [trieI, 0, childI + TRIE_NODE_CHILDREN_IDX];\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/trie\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const numVals = MAX_STATIONS * maxWorkers + 1;\n let bpe = Uint32Array.BYTES_PER_ELEMENT;\n const counts = new Uint32Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Int16Array.BYTES_PER_ELEMENT;\n const maxes = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n const mins = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Float64Array.BYTES_PER_ELEMENT;\n const sums = new Float64Array(new SharedArrayBuffer(bpe * numVals));\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n counts,\n end,\n filePath,\n id,\n maxes,\n mins,\n start,\n sums,\n } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n tries[res.id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 1; i < maxWorkers; ++i) {\n mergeLeft(tries, 0, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(ai: number, bi: number): void {\n counts[ai] += counts[bi];\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n mins[ai] = Math.min(mins[ai], mins[bi]);\n sums[ai] += sums[bi];\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi] / counts[vi]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX_IDX, TRIE_NULL } from \"./constants/trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: WorkerRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n counts[index] = 1;\n maxes[index] = temp;\n mins[index] = temp;\n sums[index] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n ++counts[index];\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n sums[index] += temp;\n }\n\n return { id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n return ++min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [res.trie.buffer]);\n });\n}\n"],"names":["open","at","bt","run","Worker","createWriteStream","createReadStream","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The maximum value for the first byte of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_B0_MAX = 247;\n\n/**\n * The maximum value for the first byte of a 1-2 byte UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_B0_2B_MAX = 223;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\n/**\n * The maximum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MAX = 191;\n\n/**\n * The number of possible values for the first byte of a UTF-8 code point.\n */\nexport const UTF8_B0_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\n\n/**\n * The number of possible values for the first byte of a 1-2 byte UTF-8 code point.\n */\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\n\n/**\n * The number of possible values for noninitial bytes of a UTF-8 code point.\n */\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","// Trie static properties\n\nimport { UTF8_B0_2B_LEN } from \"./utf8\";\n\n/**\n * Represents null / undefined.\n */\nexport const TRIE_NULL = 0;\n\n/**\n * The minimum size a trie.\n */\nexport const MIN_TRIE_SIZE = 524288; // 2 MiB\n\n/**\n * The default growth factor for growing the size of a trie.\n */\nexport const TRIE_GROWTH_FACTOR = 1.618; // ~phi\n\n/**\n * All trie properties are represented by 32 bits (4 bytes).\n */\nexport const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT;\n\n/**\n * The maximum number of children of any trie node.\n */\nexport const TRIE_MAX_CHILDREN = UTF8_B0_2B_LEN;\n\n// Trie child pointer properties\n\nexport const TRIE_CHILD_IDX_IDX = 0;\nexport const TRIE_CHILD_IDX_LEN = 1;\n\nexport const TRIE_CHILD_LEN = TRIE_CHILD_IDX_LEN;\n\n// Trie redirect pointer properties\n\nexport const TRIE_RED_ID_IDX = 0;\nexport const TRIE_RED_ID_LEN = 1;\n\nexport const TRIE_RED_VALUE_IDX_IDX = 1;\nexport const TRIE_RED_VALUE_IDX_LEN = 1;\n\nexport const TRIE_RED_LEN = TRIE_RED_ID_LEN + TRIE_RED_VALUE_IDX_LEN;\n\n// Trie node properties\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_LEN = 1;\n\nexport const TRIE_NODE_VALUE_IDX_IDX = 1;\nexport const TRIE_NODE_VALUE_IDX_LEN = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = TRIE_CHILD_LEN * TRIE_MAX_CHILDREN;\n\nexport const TRIE_NODE_LEN =\n TRIE_NODE_ID_LEN + TRIE_NODE_VALUE_IDX_LEN + TRIE_NODE_CHILDREN_LEN;\n\n// Trie properties\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_LEN = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_LEN = TRIE_NODE_LEN;\n\nexport const TRIE_HEADER_LEN = TRIE_SIZE_LEN + TRIE_ROOT_LEN;\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n MIN_TRIE_SIZE,\n TRIE_CHILD_LEN,\n TRIE_CHILD_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_HEADER_LEN,\n TRIE_ID_IDX,\n TRIE_MAX_CHILDREN,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_CHILDREN_LEN,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_LEN,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_RED_LEN,\n TRIE_RED_VALUE_IDX_IDX,\n TRIE_RED_ID_IDX,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_LEN * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_CHILD_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_LEN > trie.length) {\n trie = grow(trie, child + TRIE_NODE_LEN);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_LEN;\n // Attach and initialize node\n trie[index + TRIE_CHILD_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array {\n const minSize = TRIE_HEADER_LEN;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n console.log(\"D\");\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_LEN;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_CHILD_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_RED_LEN > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_RED_LEN);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_RED_LEN;\n // Add new redirect\n tries[at][li + TRIE_RED_ID_IDX] = rt;\n tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, 0, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childKey, childPtr] = stack[top];\n\n // Check if end of children array\n if (childKey >= TRIE_MAX_CHILDREN) {\n --top;\n continue;\n }\n\n // Update stack top\n ++stack[top][1];\n stack[top][2] += TRIE_CHILD_LEN;\n\n // If just reached node\n if (childKey === 0) {\n // Check if the node has a value\n const nodeIndex = childPtr - TRIE_NODE_CHILDREN_IDX;\n const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print the node's value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n }\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX];\n if (childI !== TRIE_NULL) {\n // Resolve child if redirect\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX];\n trieI = childTrieI;\n }\n // Add the child to the stack\n key[top] = childKey + UTF8_B0_MIN;\n stack[++top] = [trieI, 0, childI + TRIE_NODE_CHILDREN_IDX];\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/utf8Trie\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const numVals = MAX_STATIONS * maxWorkers + 1;\n let bpe = Uint32Array.BYTES_PER_ELEMENT;\n const counts = new Uint32Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Int16Array.BYTES_PER_ELEMENT;\n const maxes = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n const mins = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Float64Array.BYTES_PER_ELEMENT;\n const sums = new Float64Array(new SharedArrayBuffer(bpe * numVals));\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n counts,\n end,\n filePath,\n id,\n maxes,\n mins,\n start,\n sums,\n } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n tries[res.id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 1; i < maxWorkers; ++i) {\n mergeLeft(tries, 0, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(ai: number, bi: number): void {\n counts[ai] += counts[bi];\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n mins[ai] = Math.min(mins[ai], mins[bi]);\n sums[ai] += sums[bi];\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi] / counts[vi]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: WorkerRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n counts[index] = 1;\n maxes[index] = temp;\n mins[index] = temp;\n sums[index] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n ++counts[index];\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n sums[index] += temp;\n }\n\n return { id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n return ++min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [res.trie.buffer]);\n });\n}\n"],"names":["open","at","bt","run","Worker","createWriteStream","createReadStream","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index e51941a..505c172 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -12,9 +12,9 @@ const CHAR_MINUS = 45; const CHAR_NEWLINE = 10; const CHAR_SEMICOLON = 59; const CHAR_ZERO = 48; -const UTF8_2B_MAX = 224; -const UTF8_PRINT_OFFSET = 32; -const UTF8_2B_PRINT_MAX = UTF8_2B_MAX - UTF8_PRINT_OFFSET; +const UTF8_B0_MIN = 32; +const UTF8_B0_2B_MAX = 223; +const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1; const HIGH_WATER_MARK_MIN = 16384; const HIGH_WATER_MARK_MAX = 1048576; @@ -65,7 +65,7 @@ function getHighWaterMark(size) { const TRIE_NULL = 0; const MIN_TRIE_SIZE = 524288; const TRIE_GROWTH_FACTOR = 1.618; -const TRIE_MAX_CHILDREN = UTF8_2B_PRINT_MAX; +const TRIE_MAX_CHILDREN = UTF8_B0_2B_LEN; const TRIE_CHILD_IDX_IDX = 0; const TRIE_CHILD_IDX_LEN = 1; const TRIE_CHILD_LEN = TRIE_CHILD_IDX_LEN; @@ -91,7 +91,7 @@ const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX; function add(trie, key, min, max) { let index = TRIE_ROOT_IDX; while (min < max) { - index += TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_LEN * (key[min++] - UTF8_PRINT_OFFSET); + index += TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_LEN * (key[min++] - UTF8_B0_MIN); let child = trie[index + TRIE_CHILD_IDX_IDX]; if (child === TRIE_NULL) { child = trie[TRIE_SIZE_IDX]; @@ -208,7 +208,7 @@ function print(tries, key, trieIndex, stream, separator = "", callbackFn) { childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX]; trieI = childTrieI; } - key[top] = childKey + UTF8_PRINT_OFFSET; + key[top] = childKey + UTF8_B0_MIN; stack[++top] = [trieI, 0, childI + TRIE_NODE_CHILDREN_IDX]; } } while (top >= 0); diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index a86b9cb..277b20e 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1 +1 @@ -{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/trie.ts","../src/utils/trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n/**\n * The maximum value of a byte for UTF-8 code points of up to 2 bytes.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_2B_MAX = 224;\n\n/**\n * The number of non-printable control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_PRINT_OFFSET = 32;\n\n/**\n * The number of printable byte values for UTF-8 code points of up to 2 bytes.\n */\nexport const UTF8_2B_PRINT_MAX = UTF8_2B_MAX - UTF8_PRINT_OFFSET;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_2B_PRINT_MAX } from \"./utf8\";\n\n// Trie static properties\n\n/**\n * Represents null / undefined.\n */\nexport const TRIE_NULL = 0;\n\n/**\n * The minimum size a trie.\n */\nexport const MIN_TRIE_SIZE = 524288; // 2 MiB\n\n/**\n * The default growth factor for growing the size of a trie.\n */\nexport const TRIE_GROWTH_FACTOR = 1.618; // ~phi\n\n/**\n * All trie properties are represented by 32 bits (4 bytes).\n */\nexport const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT;\n\n/**\n * The maximum number of children of any trie node.\n */\nexport const TRIE_MAX_CHILDREN = UTF8_2B_PRINT_MAX;\n\n// Trie child pointer properties\n\nexport const TRIE_CHILD_IDX_IDX = 0;\nexport const TRIE_CHILD_IDX_LEN = 1;\n\nexport const TRIE_CHILD_LEN = TRIE_CHILD_IDX_LEN;\n\n// Trie redirect pointer properties\n\nexport const TRIE_RED_ID_IDX = 0;\nexport const TRIE_RED_ID_LEN = 1;\n\nexport const TRIE_RED_VALUE_IDX_IDX = 1;\nexport const TRIE_RED_VALUE_IDX_LEN = 1;\n\nexport const TRIE_RED_LEN = TRIE_RED_ID_LEN + TRIE_RED_VALUE_IDX_LEN;\n\n// Trie node properties\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_LEN = 1;\n\nexport const TRIE_NODE_VALUE_IDX_IDX = 1;\nexport const TRIE_NODE_VALUE_IDX_LEN = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = TRIE_CHILD_LEN * TRIE_MAX_CHILDREN;\n\nexport const TRIE_NODE_LEN =\n TRIE_NODE_ID_LEN + TRIE_NODE_VALUE_IDX_LEN + TRIE_NODE_CHILDREN_LEN;\n\n// Trie properties\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_LEN = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_LEN = TRIE_NODE_LEN;\n\nexport const TRIE_HEADER_LEN = TRIE_SIZE_LEN + TRIE_ROOT_LEN;\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n MIN_TRIE_SIZE,\n TRIE_CHILD_LEN,\n TRIE_CHILD_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_HEADER_LEN,\n TRIE_ID_IDX,\n TRIE_MAX_CHILDREN,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_CHILDREN_LEN,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_LEN,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_RED_LEN,\n TRIE_RED_VALUE_IDX_IDX,\n TRIE_RED_ID_IDX,\n} from \"../constants/trie\";\nimport { UTF8_PRINT_OFFSET } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX +\n TRIE_CHILD_LEN * (key[min++] - UTF8_PRINT_OFFSET);\n let child = trie[index + TRIE_CHILD_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_LEN > trie.length) {\n trie = grow(trie, child + TRIE_NODE_LEN);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_LEN;\n // Attach and initialize node\n trie[index + TRIE_CHILD_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array {\n const minSize = TRIE_HEADER_LEN;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n console.log(\"D\");\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_LEN;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_CHILD_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_RED_LEN > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_RED_LEN);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_RED_LEN;\n // Add new redirect\n tries[at][li + TRIE_RED_ID_IDX] = rt;\n tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, 0, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childKey, childPtr] = stack[top];\n\n // Check if end of children array\n if (childKey >= TRIE_MAX_CHILDREN) {\n --top;\n continue;\n }\n\n // Update stack top\n ++stack[top][1];\n stack[top][2] += TRIE_CHILD_LEN;\n\n // If just reached node\n if (childKey === 0) {\n // Check if the node has a value\n const nodeIndex = childPtr - TRIE_NODE_CHILDREN_IDX;\n const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print the node's value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n }\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX];\n if (childI !== TRIE_NULL) {\n // Resolve child if redirect\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX];\n trieI = childTrieI;\n }\n // Add the child to the stack\n key[top] = childKey + UTF8_PRINT_OFFSET;\n stack[++top] = [trieI, 0, childI + TRIE_NODE_CHILDREN_IDX];\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/trie\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const numVals = MAX_STATIONS * maxWorkers + 1;\n let bpe = Uint32Array.BYTES_PER_ELEMENT;\n const counts = new Uint32Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Int16Array.BYTES_PER_ELEMENT;\n const maxes = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n const mins = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Float64Array.BYTES_PER_ELEMENT;\n const sums = new Float64Array(new SharedArrayBuffer(bpe * numVals));\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n counts,\n end,\n filePath,\n id,\n maxes,\n mins,\n start,\n sums,\n } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n tries[res.id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 1; i < maxWorkers; ++i) {\n mergeLeft(tries, 0, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(ai: number, bi: number): void {\n counts[ai] += counts[bi];\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n mins[ai] = Math.min(mins[ai], mins[bi]);\n sums[ai] += sums[bi];\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi] / counts[vi]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX_IDX, TRIE_NULL } from \"./constants/trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: WorkerRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n counts[index] = 1;\n maxes[index] = temp;\n mins[index] = temp;\n sums[index] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n ++counts[index];\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n sums[index] += temp;\n }\n\n return { id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n return ++min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [res.trie.buffer]);\n });\n}\n"],"names":["at","bt","run","runMain","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The maximum value for the first byte of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_B0_MAX = 247;\n\n/**\n * The maximum value for the first byte of a 1-2 byte UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_B0_2B_MAX = 223;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\n/**\n * The maximum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MAX = 191;\n\n/**\n * The number of possible values for the first byte of a UTF-8 code point.\n */\nexport const UTF8_B0_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\n\n/**\n * The number of possible values for the first byte of a 1-2 byte UTF-8 code point.\n */\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\n\n/**\n * The number of possible values for noninitial bytes of a UTF-8 code point.\n */\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","// Trie static properties\n\nimport { UTF8_B0_2B_LEN } from \"./utf8\";\n\n/**\n * Represents null / undefined.\n */\nexport const TRIE_NULL = 0;\n\n/**\n * The minimum size a trie.\n */\nexport const MIN_TRIE_SIZE = 524288; // 2 MiB\n\n/**\n * The default growth factor for growing the size of a trie.\n */\nexport const TRIE_GROWTH_FACTOR = 1.618; // ~phi\n\n/**\n * All trie properties are represented by 32 bits (4 bytes).\n */\nexport const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT;\n\n/**\n * The maximum number of children of any trie node.\n */\nexport const TRIE_MAX_CHILDREN = UTF8_B0_2B_LEN;\n\n// Trie child pointer properties\n\nexport const TRIE_CHILD_IDX_IDX = 0;\nexport const TRIE_CHILD_IDX_LEN = 1;\n\nexport const TRIE_CHILD_LEN = TRIE_CHILD_IDX_LEN;\n\n// Trie redirect pointer properties\n\nexport const TRIE_RED_ID_IDX = 0;\nexport const TRIE_RED_ID_LEN = 1;\n\nexport const TRIE_RED_VALUE_IDX_IDX = 1;\nexport const TRIE_RED_VALUE_IDX_LEN = 1;\n\nexport const TRIE_RED_LEN = TRIE_RED_ID_LEN + TRIE_RED_VALUE_IDX_LEN;\n\n// Trie node properties\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_LEN = 1;\n\nexport const TRIE_NODE_VALUE_IDX_IDX = 1;\nexport const TRIE_NODE_VALUE_IDX_LEN = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = TRIE_CHILD_LEN * TRIE_MAX_CHILDREN;\n\nexport const TRIE_NODE_LEN =\n TRIE_NODE_ID_LEN + TRIE_NODE_VALUE_IDX_LEN + TRIE_NODE_CHILDREN_LEN;\n\n// Trie properties\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_LEN = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_LEN = TRIE_NODE_LEN;\n\nexport const TRIE_HEADER_LEN = TRIE_SIZE_LEN + TRIE_ROOT_LEN;\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n MIN_TRIE_SIZE,\n TRIE_CHILD_LEN,\n TRIE_CHILD_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_HEADER_LEN,\n TRIE_ID_IDX,\n TRIE_MAX_CHILDREN,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_CHILDREN_LEN,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_LEN,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_RED_LEN,\n TRIE_RED_VALUE_IDX_IDX,\n TRIE_RED_ID_IDX,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_LEN * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_CHILD_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_LEN > trie.length) {\n trie = grow(trie, child + TRIE_NODE_LEN);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_LEN;\n // Attach and initialize node\n trie[index + TRIE_CHILD_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array {\n const minSize = TRIE_HEADER_LEN;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n console.log(\"D\");\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_LEN;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_CHILD_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_RED_LEN > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_RED_LEN);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_RED_LEN;\n // Add new redirect\n tries[at][li + TRIE_RED_ID_IDX] = rt;\n tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, 0, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childKey, childPtr] = stack[top];\n\n // Check if end of children array\n if (childKey >= TRIE_MAX_CHILDREN) {\n --top;\n continue;\n }\n\n // Update stack top\n ++stack[top][1];\n stack[top][2] += TRIE_CHILD_LEN;\n\n // If just reached node\n if (childKey === 0) {\n // Check if the node has a value\n const nodeIndex = childPtr - TRIE_NODE_CHILDREN_IDX;\n const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print the node's value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n }\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX];\n if (childI !== TRIE_NULL) {\n // Resolve child if redirect\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX];\n trieI = childTrieI;\n }\n // Add the child to the stack\n key[top] = childKey + UTF8_B0_MIN;\n stack[++top] = [trieI, 0, childI + TRIE_NODE_CHILDREN_IDX];\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/utf8Trie\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const numVals = MAX_STATIONS * maxWorkers + 1;\n let bpe = Uint32Array.BYTES_PER_ELEMENT;\n const counts = new Uint32Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Int16Array.BYTES_PER_ELEMENT;\n const maxes = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n const mins = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Float64Array.BYTES_PER_ELEMENT;\n const sums = new Float64Array(new SharedArrayBuffer(bpe * numVals));\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n counts,\n end,\n filePath,\n id,\n maxes,\n mins,\n start,\n sums,\n } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n tries[res.id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 1; i < maxWorkers; ++i) {\n mergeLeft(tries, 0, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(ai: number, bi: number): void {\n counts[ai] += counts[bi];\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n mins[ai] = Math.min(mins[ai], mins[bi]);\n sums[ai] += sums[bi];\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi] / counts[vi]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: WorkerRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n counts[index] = 1;\n maxes[index] = temp;\n mins[index] = temp;\n sums[index] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n ++counts[index];\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n sums[index] += temp;\n }\n\n return { id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n return ++min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [res.trie.buffer]);\n });\n}\n"],"names":["at","bt","run","runMain","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/src/constants/utf8.ts b/src/main/nodejs/havelessbemore/src/constants/utf8.ts index 6e70dee..22b979c 100644 --- a/src/main/nodejs/havelessbemore/src/constants/utf8.ts +++ b/src/main/nodejs/havelessbemore/src/constants/utf8.ts @@ -24,20 +24,53 @@ export const CHAR_SEMICOLON = 59; // ";".charCodeAt(0); export const CHAR_ZERO = 48; // "0".charCodeAt(0); /** - * The maximum value of a byte for UTF-8 code points of up to 2 bytes. + * The minimum value of the first byte of a UTF-8 code point. + * + * Ignores the control code points from U+0000 to U+001F. + * + * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset} + */ +export const UTF8_B0_MIN = 32; + +/** + * The maximum value for the first byte of a UTF-8 code point. * * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding} */ -export const UTF8_2B_MAX = 224; +export const UTF8_B0_MAX = 247; /** - * The number of non-printable control code points from U+0000 to U+001F. + * The maximum value for the first byte of a 1-2 byte UTF-8 code point. * - * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset} + * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding} + */ +export const UTF8_B0_2B_MAX = 223; + +/** + * The minimum value for noninitial bytes of a UTF-8 code point. + * + * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding} + */ +export const UTF8_BN_MIN = 128; + +/** + * The maximum value for noninitial bytes of a UTF-8 code point. + * + * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding} + */ +export const UTF8_BN_MAX = 191; + +/** + * The number of possible values for the first byte of a UTF-8 code point. + */ +export const UTF8_B0_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1; + +/** + * The number of possible values for the first byte of a 1-2 byte UTF-8 code point. */ -export const UTF8_PRINT_OFFSET = 32; +export const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1; /** - * The number of printable byte values for UTF-8 code points of up to 2 bytes. + * The number of possible values for noninitial bytes of a UTF-8 code point. */ -export const UTF8_2B_PRINT_MAX = UTF8_2B_MAX - UTF8_PRINT_OFFSET; +export const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1; diff --git a/src/main/nodejs/havelessbemore/src/constants/trie.ts b/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts similarity index 94% rename from src/main/nodejs/havelessbemore/src/constants/trie.ts rename to src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts index a786190..0e0080d 100644 --- a/src/main/nodejs/havelessbemore/src/constants/trie.ts +++ b/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts @@ -1,7 +1,7 @@ -import { UTF8_2B_PRINT_MAX } from "./utf8"; - // Trie static properties +import { UTF8_B0_2B_LEN } from "./utf8"; + /** * Represents null / undefined. */ @@ -25,7 +25,7 @@ export const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT; /** * The maximum number of children of any trie node. */ -export const TRIE_MAX_CHILDREN = UTF8_2B_PRINT_MAX; +export const TRIE_MAX_CHILDREN = UTF8_B0_2B_LEN; // Trie child pointer properties diff --git a/src/main/nodejs/havelessbemore/src/main.ts b/src/main/nodejs/havelessbemore/src/main.ts index 1fa9848..9715102 100644 --- a/src/main/nodejs/havelessbemore/src/main.ts +++ b/src/main/nodejs/havelessbemore/src/main.ts @@ -12,7 +12,7 @@ import { import { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from "./constants/stream"; import { MAX_WORKERS, MIN_WORKERS } from "./constants/workers"; import { clamp, getFileChunks } from "./utils/stream"; -import { mergeLeft, print } from "./utils/trie"; +import { mergeLeft, print } from "./utils/utf8Trie"; export async function run( filePath: string, diff --git a/src/main/nodejs/havelessbemore/src/utils/trie.ts b/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts similarity index 96% rename from src/main/nodejs/havelessbemore/src/utils/trie.ts rename to src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts index 2ef1c54..0ec65bf 100644 --- a/src/main/nodejs/havelessbemore/src/utils/trie.ts +++ b/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts @@ -19,8 +19,8 @@ import { TRIE_RED_LEN, TRIE_RED_VALUE_IDX_IDX, TRIE_RED_ID_IDX, -} from "../constants/trie"; -import { UTF8_PRINT_OFFSET } from "../constants/utf8"; +} from "../constants/utf8Trie"; +import { UTF8_B0_MIN } from "../constants/utf8"; export function add( trie: Int32Array, @@ -31,8 +31,7 @@ export function add( let index = TRIE_ROOT_IDX; while (min < max) { index += - TRIE_NODE_CHILDREN_IDX + - TRIE_CHILD_LEN * (key[min++] - UTF8_PRINT_OFFSET); + TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_LEN * (key[min++] - UTF8_B0_MIN); let child = trie[index + TRIE_CHILD_IDX_IDX]; if (child === TRIE_NULL) { // Allocate new node @@ -206,7 +205,7 @@ export function print( trieI = childTrieI; } // Add the child to the stack - key[top] = childKey + UTF8_PRINT_OFFSET; + key[top] = childKey + UTF8_B0_MIN; stack[++top] = [trieI, 0, childI + TRIE_NODE_CHILDREN_IDX]; } } while (top >= 0); diff --git a/src/main/nodejs/havelessbemore/src/worker.ts b/src/main/nodejs/havelessbemore/src/worker.ts index 37b1016..dca5ce4 100644 --- a/src/main/nodejs/havelessbemore/src/worker.ts +++ b/src/main/nodejs/havelessbemore/src/worker.ts @@ -8,9 +8,9 @@ import { CHAR_NEWLINE } from "./constants/utf8"; import { CHAR_MINUS } from "./constants/utf8"; import { ENTRY_MAX_LEN, MAX_STATIONS } from "./constants/constraints"; import { CHAR_ZERO_11, CHAR_ZERO_111 } from "./constants/stream"; -import { TRIE_NODE_VALUE_IDX_IDX, TRIE_NULL } from "./constants/trie"; +import { TRIE_NODE_VALUE_IDX_IDX, TRIE_NULL } from "./constants/utf8Trie"; import { getHighWaterMark } from "./utils/stream"; -import { add, createTrie } from "./utils/trie"; +import { add, createTrie } from "./utils/utf8Trie"; export async function run({ end, From 128a8a21c04e009f6b1694b81654974f42af902c Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Wed, 22 May 2024 14:10:37 -0400 Subject: [PATCH 06/69] Refactor utf8 constants --- src/main/nodejs/havelessbemore/dist/index.cjs | 18 +++--- .../nodejs/havelessbemore/dist/index.cjs.map | 2 +- src/main/nodejs/havelessbemore/dist/index.mjs | 18 +++--- .../nodejs/havelessbemore/dist/index.mjs.map | 2 +- .../havelessbemore/src/constants/utf8.ts | 56 +++++++++---------- .../havelessbemore/src/constants/utf8Trie.ts | 22 +++++--- .../havelessbemore/src/utils/utf8Trie.ts | 16 +++--- 7 files changed, 66 insertions(+), 68 deletions(-) diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs b/src/main/nodejs/havelessbemore/dist/index.cjs index b48e322..aa556fe 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs +++ b/src/main/nodejs/havelessbemore/dist/index.cjs @@ -68,7 +68,7 @@ function getHighWaterMark(size) { const TRIE_NULL = 0; const MIN_TRIE_SIZE = 524288; const TRIE_GROWTH_FACTOR = 1.618; -const TRIE_MAX_CHILDREN = UTF8_B0_2B_LEN; +const TRIE_TAIL_NODE_CHILDREN_NUM = UTF8_B0_2B_LEN; const TRIE_CHILD_IDX_IDX = 0; const TRIE_CHILD_IDX_LEN = 1; const TRIE_CHILD_LEN = TRIE_CHILD_IDX_LEN; @@ -82,12 +82,12 @@ const TRIE_NODE_ID_LEN = 1; const TRIE_NODE_VALUE_IDX_IDX = 1; const TRIE_NODE_VALUE_IDX_LEN = 1; const TRIE_NODE_CHILDREN_IDX = 2; -const TRIE_NODE_CHILDREN_LEN = TRIE_CHILD_LEN * TRIE_MAX_CHILDREN; -const TRIE_NODE_LEN = TRIE_NODE_ID_LEN + TRIE_NODE_VALUE_IDX_LEN + TRIE_NODE_CHILDREN_LEN; +const TRIE_TAIL_NODE_CHILDREN_LEN = TRIE_CHILD_LEN * TRIE_TAIL_NODE_CHILDREN_NUM; +const TRIE_TAIL_NODE_LEN = TRIE_NODE_ID_LEN + TRIE_NODE_VALUE_IDX_LEN + TRIE_TAIL_NODE_CHILDREN_LEN; const TRIE_SIZE_IDX = 0; const TRIE_SIZE_LEN = 1; const TRIE_ROOT_IDX = 1; -const TRIE_ROOT_LEN = TRIE_NODE_LEN; +const TRIE_ROOT_LEN = TRIE_TAIL_NODE_LEN; const TRIE_HEADER_LEN = TRIE_SIZE_LEN + TRIE_ROOT_LEN; const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX; @@ -98,10 +98,10 @@ function add(trie, key, min, max) { let child = trie[index + TRIE_CHILD_IDX_IDX]; if (child === TRIE_NULL) { child = trie[TRIE_SIZE_IDX]; - if (child + TRIE_NODE_LEN > trie.length) { - trie = grow(trie, child + TRIE_NODE_LEN); + if (child + TRIE_TAIL_NODE_LEN > trie.length) { + trie = grow(trie, child + TRIE_TAIL_NODE_LEN); } - trie[TRIE_SIZE_IDX] += TRIE_NODE_LEN; + trie[TRIE_SIZE_IDX] += TRIE_TAIL_NODE_LEN; trie[index + TRIE_CHILD_IDX_IDX] = child; trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX]; } @@ -145,7 +145,7 @@ function mergeLeft(tries, at, bt, mergeFn) { } ai += TRIE_NODE_CHILDREN_IDX; bi += TRIE_NODE_CHILDREN_IDX; - const bn = bi + TRIE_NODE_CHILDREN_LEN; + const bn = bi + TRIE_TAIL_NODE_CHILDREN_LEN; while (bi < bn) { let ri = tries[bt2][bi + TRIE_CHILD_IDX_IDX]; if (ri === TRIE_NULL) { @@ -187,7 +187,7 @@ function print(tries, key, trieIndex, stream, separator = "", callbackFn) { let tail = false; do { let [trieI, childKey, childPtr] = stack[top]; - if (childKey >= TRIE_MAX_CHILDREN) { + if (childKey >= TRIE_TAIL_NODE_CHILDREN_NUM) { --top; continue; } diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs.map b/src/main/nodejs/havelessbemore/dist/index.cjs.map index f70b3e7..deb37fd 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.cjs.map @@ -1 +1 @@ -{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The maximum value for the first byte of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_B0_MAX = 247;\n\n/**\n * The maximum value for the first byte of a 1-2 byte UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_B0_2B_MAX = 223;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\n/**\n * The maximum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MAX = 191;\n\n/**\n * The number of possible values for the first byte of a UTF-8 code point.\n */\nexport const UTF8_B0_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\n\n/**\n * The number of possible values for the first byte of a 1-2 byte UTF-8 code point.\n */\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\n\n/**\n * The number of possible values for noninitial bytes of a UTF-8 code point.\n */\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","// Trie static properties\n\nimport { UTF8_B0_2B_LEN } from \"./utf8\";\n\n/**\n * Represents null / undefined.\n */\nexport const TRIE_NULL = 0;\n\n/**\n * The minimum size a trie.\n */\nexport const MIN_TRIE_SIZE = 524288; // 2 MiB\n\n/**\n * The default growth factor for growing the size of a trie.\n */\nexport const TRIE_GROWTH_FACTOR = 1.618; // ~phi\n\n/**\n * All trie properties are represented by 32 bits (4 bytes).\n */\nexport const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT;\n\n/**\n * The maximum number of children of any trie node.\n */\nexport const TRIE_MAX_CHILDREN = UTF8_B0_2B_LEN;\n\n// Trie child pointer properties\n\nexport const TRIE_CHILD_IDX_IDX = 0;\nexport const TRIE_CHILD_IDX_LEN = 1;\n\nexport const TRIE_CHILD_LEN = TRIE_CHILD_IDX_LEN;\n\n// Trie redirect pointer properties\n\nexport const TRIE_RED_ID_IDX = 0;\nexport const TRIE_RED_ID_LEN = 1;\n\nexport const TRIE_RED_VALUE_IDX_IDX = 1;\nexport const TRIE_RED_VALUE_IDX_LEN = 1;\n\nexport const TRIE_RED_LEN = TRIE_RED_ID_LEN + TRIE_RED_VALUE_IDX_LEN;\n\n// Trie node properties\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_LEN = 1;\n\nexport const TRIE_NODE_VALUE_IDX_IDX = 1;\nexport const TRIE_NODE_VALUE_IDX_LEN = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = TRIE_CHILD_LEN * TRIE_MAX_CHILDREN;\n\nexport const TRIE_NODE_LEN =\n TRIE_NODE_ID_LEN + TRIE_NODE_VALUE_IDX_LEN + TRIE_NODE_CHILDREN_LEN;\n\n// Trie properties\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_LEN = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_LEN = TRIE_NODE_LEN;\n\nexport const TRIE_HEADER_LEN = TRIE_SIZE_LEN + TRIE_ROOT_LEN;\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n MIN_TRIE_SIZE,\n TRIE_CHILD_LEN,\n TRIE_CHILD_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_HEADER_LEN,\n TRIE_ID_IDX,\n TRIE_MAX_CHILDREN,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_CHILDREN_LEN,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_LEN,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_RED_LEN,\n TRIE_RED_VALUE_IDX_IDX,\n TRIE_RED_ID_IDX,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_LEN * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_CHILD_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_LEN > trie.length) {\n trie = grow(trie, child + TRIE_NODE_LEN);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_LEN;\n // Attach and initialize node\n trie[index + TRIE_CHILD_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array {\n const minSize = TRIE_HEADER_LEN;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n console.log(\"D\");\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_LEN;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_CHILD_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_RED_LEN > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_RED_LEN);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_RED_LEN;\n // Add new redirect\n tries[at][li + TRIE_RED_ID_IDX] = rt;\n tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, 0, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childKey, childPtr] = stack[top];\n\n // Check if end of children array\n if (childKey >= TRIE_MAX_CHILDREN) {\n --top;\n continue;\n }\n\n // Update stack top\n ++stack[top][1];\n stack[top][2] += TRIE_CHILD_LEN;\n\n // If just reached node\n if (childKey === 0) {\n // Check if the node has a value\n const nodeIndex = childPtr - TRIE_NODE_CHILDREN_IDX;\n const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print the node's value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n }\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX];\n if (childI !== TRIE_NULL) {\n // Resolve child if redirect\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX];\n trieI = childTrieI;\n }\n // Add the child to the stack\n key[top] = childKey + UTF8_B0_MIN;\n stack[++top] = [trieI, 0, childI + TRIE_NODE_CHILDREN_IDX];\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/utf8Trie\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const numVals = MAX_STATIONS * maxWorkers + 1;\n let bpe = Uint32Array.BYTES_PER_ELEMENT;\n const counts = new Uint32Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Int16Array.BYTES_PER_ELEMENT;\n const maxes = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n const mins = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Float64Array.BYTES_PER_ELEMENT;\n const sums = new Float64Array(new SharedArrayBuffer(bpe * numVals));\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n counts,\n end,\n filePath,\n id,\n maxes,\n mins,\n start,\n sums,\n } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n tries[res.id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 1; i < maxWorkers; ++i) {\n mergeLeft(tries, 0, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(ai: number, bi: number): void {\n counts[ai] += counts[bi];\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n mins[ai] = Math.min(mins[ai], mins[bi]);\n sums[ai] += sums[bi];\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi] / counts[vi]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: WorkerRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n counts[index] = 1;\n maxes[index] = temp;\n mins[index] = temp;\n sums[index] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n ++counts[index];\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n sums[index] += temp;\n }\n\n return { id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n return ++min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [res.trie.buffer]);\n });\n}\n"],"names":["open","at","bt","run","Worker","createWriteStream","createReadStream","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","// Trie static properties\n\nimport { UTF8_B0_2B_LEN, UTF8_BN_LEN } from \"./utf8\";\n\n/**\n * Represents null / undefined.\n */\nexport const TRIE_NULL = 0;\n\n/**\n * The minimum size a trie.\n */\nexport const MIN_TRIE_SIZE = 524288; // 2 MiB\n\n/**\n * The default growth factor for growing the size of a trie.\n */\nexport const TRIE_GROWTH_FACTOR = 1.618; // ~phi\n\n/**\n * All trie properties are represented by 32 bits (4 bytes).\n */\nexport const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT;\n\nexport const TRIE_BODY_NODE_CHILDREN_NUM = UTF8_BN_LEN;\nexport const TRIE_TAIL_NODE_CHILDREN_NUM = UTF8_B0_2B_LEN;\n\n// Trie child pointer properties\n\nexport const TRIE_CHILD_IDX_IDX = 0;\nexport const TRIE_CHILD_IDX_LEN = 1;\n\nexport const TRIE_CHILD_LEN = TRIE_CHILD_IDX_LEN;\n\n// Trie redirect pointer properties\n\nexport const TRIE_RED_ID_IDX = 0;\nexport const TRIE_RED_ID_LEN = 1;\n\nexport const TRIE_RED_VALUE_IDX_IDX = 1;\nexport const TRIE_RED_VALUE_IDX_LEN = 1;\n\nexport const TRIE_RED_LEN = TRIE_RED_ID_LEN + TRIE_RED_VALUE_IDX_LEN;\n\n// Trie node properties\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_LEN = 1;\n\nexport const TRIE_NODE_VALUE_IDX_IDX = 1;\nexport const TRIE_NODE_VALUE_IDX_LEN = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_BODY_NODE_CHILDREN_LEN =\n TRIE_CHILD_LEN * TRIE_BODY_NODE_CHILDREN_NUM;\nexport const TRIE_TAIL_NODE_CHILDREN_LEN =\n TRIE_CHILD_LEN * TRIE_TAIL_NODE_CHILDREN_NUM;\n\nexport const TRIE_BODY_NODE_LEN =\n TRIE_NODE_ID_LEN + TRIE_NODE_VALUE_IDX_LEN + TRIE_BODY_NODE_CHILDREN_LEN;\n\nexport const TRIE_TAIL_NODE_LEN =\n TRIE_NODE_ID_LEN + TRIE_NODE_VALUE_IDX_LEN + TRIE_TAIL_NODE_CHILDREN_LEN;\n\n// Trie properties\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_LEN = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_LEN = TRIE_TAIL_NODE_LEN;\n\nexport const TRIE_HEADER_LEN = TRIE_SIZE_LEN + TRIE_ROOT_LEN;\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n MIN_TRIE_SIZE,\n TRIE_CHILD_LEN,\n TRIE_CHILD_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_HEADER_LEN,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_RED_LEN,\n TRIE_RED_VALUE_IDX_IDX,\n TRIE_RED_ID_IDX,\n TRIE_TAIL_NODE_CHILDREN_NUM,\n TRIE_TAIL_NODE_CHILDREN_LEN,\n TRIE_TAIL_NODE_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_LEN * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_CHILD_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_TAIL_NODE_LEN > trie.length) {\n trie = grow(trie, child + TRIE_TAIL_NODE_LEN);\n }\n trie[TRIE_SIZE_IDX] += TRIE_TAIL_NODE_LEN;\n // Attach and initialize node\n trie[index + TRIE_CHILD_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array {\n const minSize = TRIE_HEADER_LEN;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n console.log(\"D\");\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_TAIL_NODE_CHILDREN_LEN;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_CHILD_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_RED_LEN > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_RED_LEN);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_RED_LEN;\n // Add new redirect\n tries[at][li + TRIE_RED_ID_IDX] = rt;\n tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, 0, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childKey, childPtr] = stack[top];\n\n // Check if end of children array\n if (childKey >= TRIE_TAIL_NODE_CHILDREN_NUM) {\n --top;\n continue;\n }\n\n // Update stack top\n ++stack[top][1];\n stack[top][2] += TRIE_CHILD_LEN;\n\n // If just reached node\n if (childKey === 0) {\n // Check if the node has a value\n const nodeIndex = childPtr - TRIE_NODE_CHILDREN_IDX;\n const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print the node's value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n }\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX];\n if (childI !== TRIE_NULL) {\n // Resolve child if redirect\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX];\n trieI = childTrieI;\n }\n // Add the child to the stack\n key[top] = childKey + UTF8_B0_MIN;\n stack[++top] = [trieI, 0, childI + TRIE_NODE_CHILDREN_IDX];\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/utf8Trie\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const numVals = MAX_STATIONS * maxWorkers + 1;\n let bpe = Uint32Array.BYTES_PER_ELEMENT;\n const counts = new Uint32Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Int16Array.BYTES_PER_ELEMENT;\n const maxes = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n const mins = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Float64Array.BYTES_PER_ELEMENT;\n const sums = new Float64Array(new SharedArrayBuffer(bpe * numVals));\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n counts,\n end,\n filePath,\n id,\n maxes,\n mins,\n start,\n sums,\n } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n tries[res.id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 1; i < maxWorkers; ++i) {\n mergeLeft(tries, 0, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(ai: number, bi: number): void {\n counts[ai] += counts[bi];\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n mins[ai] = Math.min(mins[ai], mins[bi]);\n sums[ai] += sums[bi];\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi] / counts[vi]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: WorkerRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n counts[index] = 1;\n maxes[index] = temp;\n mins[index] = temp;\n sums[index] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n ++counts[index];\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n sums[index] += temp;\n }\n\n return { id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n return ++min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [res.trie.buffer]);\n });\n}\n"],"names":["open","at","bt","run","Worker","createWriteStream","createReadStream","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index 505c172..8d9e899 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -65,7 +65,7 @@ function getHighWaterMark(size) { const TRIE_NULL = 0; const MIN_TRIE_SIZE = 524288; const TRIE_GROWTH_FACTOR = 1.618; -const TRIE_MAX_CHILDREN = UTF8_B0_2B_LEN; +const TRIE_TAIL_NODE_CHILDREN_NUM = UTF8_B0_2B_LEN; const TRIE_CHILD_IDX_IDX = 0; const TRIE_CHILD_IDX_LEN = 1; const TRIE_CHILD_LEN = TRIE_CHILD_IDX_LEN; @@ -79,12 +79,12 @@ const TRIE_NODE_ID_LEN = 1; const TRIE_NODE_VALUE_IDX_IDX = 1; const TRIE_NODE_VALUE_IDX_LEN = 1; const TRIE_NODE_CHILDREN_IDX = 2; -const TRIE_NODE_CHILDREN_LEN = TRIE_CHILD_LEN * TRIE_MAX_CHILDREN; -const TRIE_NODE_LEN = TRIE_NODE_ID_LEN + TRIE_NODE_VALUE_IDX_LEN + TRIE_NODE_CHILDREN_LEN; +const TRIE_TAIL_NODE_CHILDREN_LEN = TRIE_CHILD_LEN * TRIE_TAIL_NODE_CHILDREN_NUM; +const TRIE_TAIL_NODE_LEN = TRIE_NODE_ID_LEN + TRIE_NODE_VALUE_IDX_LEN + TRIE_TAIL_NODE_CHILDREN_LEN; const TRIE_SIZE_IDX = 0; const TRIE_SIZE_LEN = 1; const TRIE_ROOT_IDX = 1; -const TRIE_ROOT_LEN = TRIE_NODE_LEN; +const TRIE_ROOT_LEN = TRIE_TAIL_NODE_LEN; const TRIE_HEADER_LEN = TRIE_SIZE_LEN + TRIE_ROOT_LEN; const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX; @@ -95,10 +95,10 @@ function add(trie, key, min, max) { let child = trie[index + TRIE_CHILD_IDX_IDX]; if (child === TRIE_NULL) { child = trie[TRIE_SIZE_IDX]; - if (child + TRIE_NODE_LEN > trie.length) { - trie = grow(trie, child + TRIE_NODE_LEN); + if (child + TRIE_TAIL_NODE_LEN > trie.length) { + trie = grow(trie, child + TRIE_TAIL_NODE_LEN); } - trie[TRIE_SIZE_IDX] += TRIE_NODE_LEN; + trie[TRIE_SIZE_IDX] += TRIE_TAIL_NODE_LEN; trie[index + TRIE_CHILD_IDX_IDX] = child; trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX]; } @@ -142,7 +142,7 @@ function mergeLeft(tries, at, bt, mergeFn) { } ai += TRIE_NODE_CHILDREN_IDX; bi += TRIE_NODE_CHILDREN_IDX; - const bn = bi + TRIE_NODE_CHILDREN_LEN; + const bn = bi + TRIE_TAIL_NODE_CHILDREN_LEN; while (bi < bn) { let ri = tries[bt2][bi + TRIE_CHILD_IDX_IDX]; if (ri === TRIE_NULL) { @@ -184,7 +184,7 @@ function print(tries, key, trieIndex, stream, separator = "", callbackFn) { let tail = false; do { let [trieI, childKey, childPtr] = stack[top]; - if (childKey >= TRIE_MAX_CHILDREN) { + if (childKey >= TRIE_TAIL_NODE_CHILDREN_NUM) { --top; continue; } diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index 277b20e..e1665d8 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1 +1 @@ -{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The maximum value for the first byte of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_B0_MAX = 247;\n\n/**\n * The maximum value for the first byte of a 1-2 byte UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_B0_2B_MAX = 223;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\n/**\n * The maximum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MAX = 191;\n\n/**\n * The number of possible values for the first byte of a UTF-8 code point.\n */\nexport const UTF8_B0_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\n\n/**\n * The number of possible values for the first byte of a 1-2 byte UTF-8 code point.\n */\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\n\n/**\n * The number of possible values for noninitial bytes of a UTF-8 code point.\n */\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","// Trie static properties\n\nimport { UTF8_B0_2B_LEN } from \"./utf8\";\n\n/**\n * Represents null / undefined.\n */\nexport const TRIE_NULL = 0;\n\n/**\n * The minimum size a trie.\n */\nexport const MIN_TRIE_SIZE = 524288; // 2 MiB\n\n/**\n * The default growth factor for growing the size of a trie.\n */\nexport const TRIE_GROWTH_FACTOR = 1.618; // ~phi\n\n/**\n * All trie properties are represented by 32 bits (4 bytes).\n */\nexport const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT;\n\n/**\n * The maximum number of children of any trie node.\n */\nexport const TRIE_MAX_CHILDREN = UTF8_B0_2B_LEN;\n\n// Trie child pointer properties\n\nexport const TRIE_CHILD_IDX_IDX = 0;\nexport const TRIE_CHILD_IDX_LEN = 1;\n\nexport const TRIE_CHILD_LEN = TRIE_CHILD_IDX_LEN;\n\n// Trie redirect pointer properties\n\nexport const TRIE_RED_ID_IDX = 0;\nexport const TRIE_RED_ID_LEN = 1;\n\nexport const TRIE_RED_VALUE_IDX_IDX = 1;\nexport const TRIE_RED_VALUE_IDX_LEN = 1;\n\nexport const TRIE_RED_LEN = TRIE_RED_ID_LEN + TRIE_RED_VALUE_IDX_LEN;\n\n// Trie node properties\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_LEN = 1;\n\nexport const TRIE_NODE_VALUE_IDX_IDX = 1;\nexport const TRIE_NODE_VALUE_IDX_LEN = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = TRIE_CHILD_LEN * TRIE_MAX_CHILDREN;\n\nexport const TRIE_NODE_LEN =\n TRIE_NODE_ID_LEN + TRIE_NODE_VALUE_IDX_LEN + TRIE_NODE_CHILDREN_LEN;\n\n// Trie properties\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_LEN = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_LEN = TRIE_NODE_LEN;\n\nexport const TRIE_HEADER_LEN = TRIE_SIZE_LEN + TRIE_ROOT_LEN;\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n MIN_TRIE_SIZE,\n TRIE_CHILD_LEN,\n TRIE_CHILD_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_HEADER_LEN,\n TRIE_ID_IDX,\n TRIE_MAX_CHILDREN,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_CHILDREN_LEN,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_LEN,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_RED_LEN,\n TRIE_RED_VALUE_IDX_IDX,\n TRIE_RED_ID_IDX,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_LEN * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_CHILD_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_LEN > trie.length) {\n trie = grow(trie, child + TRIE_NODE_LEN);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_LEN;\n // Attach and initialize node\n trie[index + TRIE_CHILD_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array {\n const minSize = TRIE_HEADER_LEN;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n console.log(\"D\");\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_LEN;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_CHILD_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_RED_LEN > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_RED_LEN);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_RED_LEN;\n // Add new redirect\n tries[at][li + TRIE_RED_ID_IDX] = rt;\n tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, 0, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childKey, childPtr] = stack[top];\n\n // Check if end of children array\n if (childKey >= TRIE_MAX_CHILDREN) {\n --top;\n continue;\n }\n\n // Update stack top\n ++stack[top][1];\n stack[top][2] += TRIE_CHILD_LEN;\n\n // If just reached node\n if (childKey === 0) {\n // Check if the node has a value\n const nodeIndex = childPtr - TRIE_NODE_CHILDREN_IDX;\n const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print the node's value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n }\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX];\n if (childI !== TRIE_NULL) {\n // Resolve child if redirect\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX];\n trieI = childTrieI;\n }\n // Add the child to the stack\n key[top] = childKey + UTF8_B0_MIN;\n stack[++top] = [trieI, 0, childI + TRIE_NODE_CHILDREN_IDX];\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/utf8Trie\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const numVals = MAX_STATIONS * maxWorkers + 1;\n let bpe = Uint32Array.BYTES_PER_ELEMENT;\n const counts = new Uint32Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Int16Array.BYTES_PER_ELEMENT;\n const maxes = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n const mins = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Float64Array.BYTES_PER_ELEMENT;\n const sums = new Float64Array(new SharedArrayBuffer(bpe * numVals));\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n counts,\n end,\n filePath,\n id,\n maxes,\n mins,\n start,\n sums,\n } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n tries[res.id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 1; i < maxWorkers; ++i) {\n mergeLeft(tries, 0, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(ai: number, bi: number): void {\n counts[ai] += counts[bi];\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n mins[ai] = Math.min(mins[ai], mins[bi]);\n sums[ai] += sums[bi];\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi] / counts[vi]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: WorkerRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n counts[index] = 1;\n maxes[index] = temp;\n mins[index] = temp;\n sums[index] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n ++counts[index];\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n sums[index] += temp;\n }\n\n return { id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n return ++min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [res.trie.buffer]);\n });\n}\n"],"names":["at","bt","run","runMain","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","// Trie static properties\n\nimport { UTF8_B0_2B_LEN, UTF8_BN_LEN } from \"./utf8\";\n\n/**\n * Represents null / undefined.\n */\nexport const TRIE_NULL = 0;\n\n/**\n * The minimum size a trie.\n */\nexport const MIN_TRIE_SIZE = 524288; // 2 MiB\n\n/**\n * The default growth factor for growing the size of a trie.\n */\nexport const TRIE_GROWTH_FACTOR = 1.618; // ~phi\n\n/**\n * All trie properties are represented by 32 bits (4 bytes).\n */\nexport const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT;\n\nexport const TRIE_BODY_NODE_CHILDREN_NUM = UTF8_BN_LEN;\nexport const TRIE_TAIL_NODE_CHILDREN_NUM = UTF8_B0_2B_LEN;\n\n// Trie child pointer properties\n\nexport const TRIE_CHILD_IDX_IDX = 0;\nexport const TRIE_CHILD_IDX_LEN = 1;\n\nexport const TRIE_CHILD_LEN = TRIE_CHILD_IDX_LEN;\n\n// Trie redirect pointer properties\n\nexport const TRIE_RED_ID_IDX = 0;\nexport const TRIE_RED_ID_LEN = 1;\n\nexport const TRIE_RED_VALUE_IDX_IDX = 1;\nexport const TRIE_RED_VALUE_IDX_LEN = 1;\n\nexport const TRIE_RED_LEN = TRIE_RED_ID_LEN + TRIE_RED_VALUE_IDX_LEN;\n\n// Trie node properties\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_LEN = 1;\n\nexport const TRIE_NODE_VALUE_IDX_IDX = 1;\nexport const TRIE_NODE_VALUE_IDX_LEN = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_BODY_NODE_CHILDREN_LEN =\n TRIE_CHILD_LEN * TRIE_BODY_NODE_CHILDREN_NUM;\nexport const TRIE_TAIL_NODE_CHILDREN_LEN =\n TRIE_CHILD_LEN * TRIE_TAIL_NODE_CHILDREN_NUM;\n\nexport const TRIE_BODY_NODE_LEN =\n TRIE_NODE_ID_LEN + TRIE_NODE_VALUE_IDX_LEN + TRIE_BODY_NODE_CHILDREN_LEN;\n\nexport const TRIE_TAIL_NODE_LEN =\n TRIE_NODE_ID_LEN + TRIE_NODE_VALUE_IDX_LEN + TRIE_TAIL_NODE_CHILDREN_LEN;\n\n// Trie properties\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_LEN = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_LEN = TRIE_TAIL_NODE_LEN;\n\nexport const TRIE_HEADER_LEN = TRIE_SIZE_LEN + TRIE_ROOT_LEN;\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n MIN_TRIE_SIZE,\n TRIE_CHILD_LEN,\n TRIE_CHILD_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_HEADER_LEN,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_RED_LEN,\n TRIE_RED_VALUE_IDX_IDX,\n TRIE_RED_ID_IDX,\n TRIE_TAIL_NODE_CHILDREN_NUM,\n TRIE_TAIL_NODE_CHILDREN_LEN,\n TRIE_TAIL_NODE_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_LEN * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_CHILD_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_TAIL_NODE_LEN > trie.length) {\n trie = grow(trie, child + TRIE_TAIL_NODE_LEN);\n }\n trie[TRIE_SIZE_IDX] += TRIE_TAIL_NODE_LEN;\n // Attach and initialize node\n trie[index + TRIE_CHILD_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array {\n const minSize = TRIE_HEADER_LEN;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n console.log(\"D\");\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_TAIL_NODE_CHILDREN_LEN;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_CHILD_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_RED_LEN > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_RED_LEN);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_RED_LEN;\n // Add new redirect\n tries[at][li + TRIE_RED_ID_IDX] = rt;\n tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, 0, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childKey, childPtr] = stack[top];\n\n // Check if end of children array\n if (childKey >= TRIE_TAIL_NODE_CHILDREN_NUM) {\n --top;\n continue;\n }\n\n // Update stack top\n ++stack[top][1];\n stack[top][2] += TRIE_CHILD_LEN;\n\n // If just reached node\n if (childKey === 0) {\n // Check if the node has a value\n const nodeIndex = childPtr - TRIE_NODE_CHILDREN_IDX;\n const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print the node's value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n }\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX];\n if (childI !== TRIE_NULL) {\n // Resolve child if redirect\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX];\n trieI = childTrieI;\n }\n // Add the child to the stack\n key[top] = childKey + UTF8_B0_MIN;\n stack[++top] = [trieI, 0, childI + TRIE_NODE_CHILDREN_IDX];\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/utf8Trie\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const numVals = MAX_STATIONS * maxWorkers + 1;\n let bpe = Uint32Array.BYTES_PER_ELEMENT;\n const counts = new Uint32Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Int16Array.BYTES_PER_ELEMENT;\n const maxes = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n const mins = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Float64Array.BYTES_PER_ELEMENT;\n const sums = new Float64Array(new SharedArrayBuffer(bpe * numVals));\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n counts,\n end,\n filePath,\n id,\n maxes,\n mins,\n start,\n sums,\n } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n tries[res.id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 1; i < maxWorkers; ++i) {\n mergeLeft(tries, 0, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(ai: number, bi: number): void {\n counts[ai] += counts[bi];\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n mins[ai] = Math.min(mins[ai], mins[bi]);\n sums[ai] += sums[bi];\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi] / counts[vi]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: WorkerRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n counts[index] = 1;\n maxes[index] = temp;\n mins[index] = temp;\n sums[index] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n ++counts[index];\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n sums[index] += temp;\n }\n\n return { id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n return ++min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [res.trie.buffer]);\n });\n}\n"],"names":["at","bt","run","runMain","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/src/constants/utf8.ts b/src/main/nodejs/havelessbemore/src/constants/utf8.ts index 22b979c..11d89d1 100644 --- a/src/main/nodejs/havelessbemore/src/constants/utf8.ts +++ b/src/main/nodejs/havelessbemore/src/constants/utf8.ts @@ -1,3 +1,5 @@ +// UTF-8 char codes + /** * The char code for a minus sign: - */ @@ -23,6 +25,8 @@ export const CHAR_SEMICOLON = 59; // ";".charCodeAt(0); */ export const CHAR_ZERO = 48; // "0".charCodeAt(0); +// UTF-8 constants + /** * The minimum value of the first byte of a UTF-8 code point. * @@ -32,20 +36,6 @@ export const CHAR_ZERO = 48; // "0".charCodeAt(0); */ export const UTF8_B0_MIN = 32; -/** - * The maximum value for the first byte of a UTF-8 code point. - * - * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding} - */ -export const UTF8_B0_MAX = 247; - -/** - * The maximum value for the first byte of a 1-2 byte UTF-8 code point. - * - * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding} - */ -export const UTF8_B0_2B_MAX = 223; - /** * The minimum value for noninitial bytes of a UTF-8 code point. * @@ -53,24 +43,28 @@ export const UTF8_B0_2B_MAX = 223; */ export const UTF8_BN_MIN = 128; -/** - * The maximum value for noninitial bytes of a UTF-8 code point. - * - * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding} - */ -export const UTF8_BN_MAX = 191; +export const UTF8_B0_1B_LEAD = 0b00000000; +export const UTF8_BN_LEAD = 0b10000000; +export const UTF8_B0_2B_LEAD = 0b11000000; +export const UTF8_B0_3B_LEAD = 0b11100000; +export const UTF8_B0_4B_LEAD = 0b11110000; -/** - * The number of possible values for the first byte of a UTF-8 code point. - */ -export const UTF8_B0_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1; +export const UTF8_B0_1B_LEAD_MASK = 0b10000000; +export const UTF8_BN_LEAD_MASK = 0b11000000; +export const UTF8_B0_2B_LEAD_MASK = 0b11100000; +export const UTF8_B0_3B_LEAD_MASK = 0b11110000; +export const UTF8_B0_4B_LEAD_MASK = 0b11111000; -/** - * The number of possible values for the first byte of a 1-2 byte UTF-8 code point. - */ -export const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1; +export const UTF8_B0_1B_MAX = 0b01111111; +export const UTF8_BN_MAX = 0b10111111; +export const UTF8_B0_2B_MAX = 0b11011111; +export const UTF8_B0_3B_MAX = 0b11101111; +export const UTF8_B0_4B_MAX = 0b11110111; +export const UTF8_B0_MAX = UTF8_B0_4B_MAX; -/** - * The number of possible values for noninitial bytes of a UTF-8 code point. - */ +export const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1; +export const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1; +export const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1; +export const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1; +export const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1; export const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1; diff --git a/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts b/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts index 0e0080d..047d3d5 100644 --- a/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts +++ b/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts @@ -1,6 +1,6 @@ // Trie static properties -import { UTF8_B0_2B_LEN } from "./utf8"; +import { UTF8_B0_2B_LEN, UTF8_BN_LEN } from "./utf8"; /** * Represents null / undefined. @@ -22,10 +22,8 @@ export const TRIE_GROWTH_FACTOR = 1.618; // ~phi */ export const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT; -/** - * The maximum number of children of any trie node. - */ -export const TRIE_MAX_CHILDREN = UTF8_B0_2B_LEN; +export const TRIE_BODY_NODE_CHILDREN_NUM = UTF8_BN_LEN; +export const TRIE_TAIL_NODE_CHILDREN_NUM = UTF8_B0_2B_LEN; // Trie child pointer properties @@ -53,10 +51,16 @@ export const TRIE_NODE_VALUE_IDX_IDX = 1; export const TRIE_NODE_VALUE_IDX_LEN = 1; export const TRIE_NODE_CHILDREN_IDX = 2; -export const TRIE_NODE_CHILDREN_LEN = TRIE_CHILD_LEN * TRIE_MAX_CHILDREN; +export const TRIE_BODY_NODE_CHILDREN_LEN = + TRIE_CHILD_LEN * TRIE_BODY_NODE_CHILDREN_NUM; +export const TRIE_TAIL_NODE_CHILDREN_LEN = + TRIE_CHILD_LEN * TRIE_TAIL_NODE_CHILDREN_NUM; + +export const TRIE_BODY_NODE_LEN = + TRIE_NODE_ID_LEN + TRIE_NODE_VALUE_IDX_LEN + TRIE_BODY_NODE_CHILDREN_LEN; -export const TRIE_NODE_LEN = - TRIE_NODE_ID_LEN + TRIE_NODE_VALUE_IDX_LEN + TRIE_NODE_CHILDREN_LEN; +export const TRIE_TAIL_NODE_LEN = + TRIE_NODE_ID_LEN + TRIE_NODE_VALUE_IDX_LEN + TRIE_TAIL_NODE_CHILDREN_LEN; // Trie properties @@ -64,7 +68,7 @@ export const TRIE_SIZE_IDX = 0; export const TRIE_SIZE_LEN = 1; export const TRIE_ROOT_IDX = 1; -export const TRIE_ROOT_LEN = TRIE_NODE_LEN; +export const TRIE_ROOT_LEN = TRIE_TAIL_NODE_LEN; export const TRIE_HEADER_LEN = TRIE_SIZE_LEN + TRIE_ROOT_LEN; export const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX; diff --git a/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts b/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts index 0ec65bf..fa83118 100644 --- a/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts +++ b/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts @@ -7,11 +7,8 @@ import { TRIE_GROWTH_FACTOR, TRIE_HEADER_LEN, TRIE_ID_IDX, - TRIE_MAX_CHILDREN, TRIE_NODE_CHILDREN_IDX, - TRIE_NODE_CHILDREN_LEN, TRIE_NODE_ID_IDX, - TRIE_NODE_LEN, TRIE_NODE_VALUE_IDX_IDX, TRIE_NULL, TRIE_ROOT_IDX, @@ -19,6 +16,9 @@ import { TRIE_RED_LEN, TRIE_RED_VALUE_IDX_IDX, TRIE_RED_ID_IDX, + TRIE_TAIL_NODE_CHILDREN_NUM, + TRIE_TAIL_NODE_CHILDREN_LEN, + TRIE_TAIL_NODE_LEN, } from "../constants/utf8Trie"; import { UTF8_B0_MIN } from "../constants/utf8"; @@ -36,10 +36,10 @@ export function add( if (child === TRIE_NULL) { // Allocate new node child = trie[TRIE_SIZE_IDX]; - if (child + TRIE_NODE_LEN > trie.length) { - trie = grow(trie, child + TRIE_NODE_LEN); + if (child + TRIE_TAIL_NODE_LEN > trie.length) { + trie = grow(trie, child + TRIE_TAIL_NODE_LEN); } - trie[TRIE_SIZE_IDX] += TRIE_NODE_LEN; + trie[TRIE_SIZE_IDX] += TRIE_TAIL_NODE_LEN; // Attach and initialize node trie[index + TRIE_CHILD_IDX_IDX] = child; trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX]; @@ -101,7 +101,7 @@ export function mergeLeft( bi += TRIE_NODE_CHILDREN_IDX; // Traverse right children - const bn = bi + TRIE_NODE_CHILDREN_LEN; + const bn = bi + TRIE_TAIL_NODE_CHILDREN_LEN; while (bi < bn) { // If right child is null let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX]; @@ -171,7 +171,7 @@ export function print( let [trieI, childKey, childPtr] = stack[top]; // Check if end of children array - if (childKey >= TRIE_MAX_CHILDREN) { + if (childKey >= TRIE_TAIL_NODE_CHILDREN_NUM) { --top; continue; } From 111786e91c740464e9e225009e805ce873619404 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Wed, 22 May 2024 14:22:51 -0400 Subject: [PATCH 07/69] Rename utf8Trie constants --- src/main/nodejs/havelessbemore/dist/index.cjs | 56 +++++++++---------- .../nodejs/havelessbemore/dist/index.cjs.map | 2 +- src/main/nodejs/havelessbemore/dist/index.mjs | 56 +++++++++---------- .../nodejs/havelessbemore/dist/index.mjs.map | 2 +- .../havelessbemore/src/constants/utf8Trie.ts | 44 +++++++-------- .../havelessbemore/src/utils/utf8Trie.ts | 40 ++++++------- 6 files changed, 100 insertions(+), 100 deletions(-) diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs b/src/main/nodejs/havelessbemore/dist/index.cjs index aa556fe..abebab9 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs +++ b/src/main/nodejs/havelessbemore/dist/index.cjs @@ -68,40 +68,40 @@ function getHighWaterMark(size) { const TRIE_NULL = 0; const MIN_TRIE_SIZE = 524288; const TRIE_GROWTH_FACTOR = 1.618; -const TRIE_TAIL_NODE_CHILDREN_NUM = UTF8_B0_2B_LEN; +const TRIE_TAIL_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN; const TRIE_CHILD_IDX_IDX = 0; -const TRIE_CHILD_IDX_LEN = 1; -const TRIE_CHILD_LEN = TRIE_CHILD_IDX_LEN; +const TRIE_CHILD_IDX_UTS = 1; +const TRIE_CHILD_UTS = TRIE_CHILD_IDX_UTS; const TRIE_RED_ID_IDX = 0; -const TRIE_RED_ID_LEN = 1; +const TRIE_RED_ID_UTS = 1; const TRIE_RED_VALUE_IDX_IDX = 1; -const TRIE_RED_VALUE_IDX_LEN = 1; -const TRIE_RED_LEN = TRIE_RED_ID_LEN + TRIE_RED_VALUE_IDX_LEN; +const TRIE_RED_VALUE_IDX_UTS = 1; +const TRIE_RED_UTS = TRIE_RED_ID_UTS + TRIE_RED_VALUE_IDX_UTS; const TRIE_NODE_ID_IDX = 0; -const TRIE_NODE_ID_LEN = 1; +const TRIE_NODE_ID_UTS = 1; const TRIE_NODE_VALUE_IDX_IDX = 1; -const TRIE_NODE_VALUE_IDX_LEN = 1; +const TRIE_NODE_VALUE_IDX_UTS = 1; const TRIE_NODE_CHILDREN_IDX = 2; -const TRIE_TAIL_NODE_CHILDREN_LEN = TRIE_CHILD_LEN * TRIE_TAIL_NODE_CHILDREN_NUM; -const TRIE_TAIL_NODE_LEN = TRIE_NODE_ID_LEN + TRIE_NODE_VALUE_IDX_LEN + TRIE_TAIL_NODE_CHILDREN_LEN; +const TRIE_TAIL_NODE_CHILDREN_UTS = TRIE_CHILD_UTS * TRIE_TAIL_NODE_CHILDREN_LEN; +const TRIE_TAIL_NODE_UTS = TRIE_NODE_ID_UTS + TRIE_NODE_VALUE_IDX_UTS + TRIE_TAIL_NODE_CHILDREN_UTS; const TRIE_SIZE_IDX = 0; -const TRIE_SIZE_LEN = 1; +const TRIE_SIZE_UTS = 1; const TRIE_ROOT_IDX = 1; -const TRIE_ROOT_LEN = TRIE_TAIL_NODE_LEN; -const TRIE_HEADER_LEN = TRIE_SIZE_LEN + TRIE_ROOT_LEN; +const TRIE_ROOT_UTS = TRIE_TAIL_NODE_UTS; const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX; +const TRIE_HEADER_UTS = TRIE_SIZE_UTS + TRIE_ROOT_UTS; function add(trie, key, min, max) { let index = TRIE_ROOT_IDX; while (min < max) { - index += TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_LEN * (key[min++] - UTF8_B0_MIN); + index += TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_UTS * (key[min++] - UTF8_B0_MIN); let child = trie[index + TRIE_CHILD_IDX_IDX]; if (child === TRIE_NULL) { child = trie[TRIE_SIZE_IDX]; - if (child + TRIE_TAIL_NODE_LEN > trie.length) { - trie = grow(trie, child + TRIE_TAIL_NODE_LEN); + if (child + TRIE_TAIL_NODE_UTS > trie.length) { + trie = grow(trie, child + TRIE_TAIL_NODE_UTS); } - trie[TRIE_SIZE_IDX] += TRIE_TAIL_NODE_LEN; + trie[TRIE_SIZE_IDX] += TRIE_TAIL_NODE_UTS; trie[index + TRIE_CHILD_IDX_IDX] = child; trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX]; } @@ -110,7 +110,7 @@ function add(trie, key, min, max) { return [trie, index]; } function createTrie(id = 0, size = MIN_TRIE_SIZE) { - const minSize = TRIE_HEADER_LEN; + const minSize = TRIE_HEADER_UTS; const trie = new Int32Array(Math.max(minSize, size)); trie[TRIE_SIZE_IDX] = minSize; trie[TRIE_ID_IDX] = id; @@ -145,12 +145,12 @@ function mergeLeft(tries, at, bt, mergeFn) { } ai += TRIE_NODE_CHILDREN_IDX; bi += TRIE_NODE_CHILDREN_IDX; - const bn = bi + TRIE_TAIL_NODE_CHILDREN_LEN; + const bn = bi + TRIE_TAIL_NODE_CHILDREN_UTS; while (bi < bn) { let ri = tries[bt2][bi + TRIE_CHILD_IDX_IDX]; if (ri === TRIE_NULL) { - ai += TRIE_CHILD_LEN; - bi += TRIE_CHILD_LEN; + ai += TRIE_CHILD_UTS; + bi += TRIE_CHILD_UTS; continue; } const rt = tries[bt2][ri + TRIE_NODE_ID_IDX]; @@ -160,10 +160,10 @@ function mergeLeft(tries, at, bt, mergeFn) { let li = tries[at2][ai + TRIE_CHILD_IDX_IDX]; if (li === TRIE_NULL) { li = tries[at2][TRIE_SIZE_IDX]; - if (li + TRIE_RED_LEN > tries[at2].length) { - tries[at2] = grow(tries[at2], li + TRIE_RED_LEN); + if (li + TRIE_RED_UTS > tries[at2].length) { + tries[at2] = grow(tries[at2], li + TRIE_RED_UTS); } - tries[at2][TRIE_SIZE_IDX] += TRIE_RED_LEN; + tries[at2][TRIE_SIZE_IDX] += TRIE_RED_UTS; tries[at2][li + TRIE_RED_ID_IDX] = rt; tries[at2][li + TRIE_RED_VALUE_IDX_IDX] = ri; } else { @@ -173,8 +173,8 @@ function mergeLeft(tries, at, bt, mergeFn) { } queue.push([lt, li, rt, ri]); } - ai += TRIE_CHILD_LEN; - bi += TRIE_CHILD_LEN; + ai += TRIE_CHILD_UTS; + bi += TRIE_CHILD_UTS; } } queue.splice(0, Q); @@ -187,12 +187,12 @@ function print(tries, key, trieIndex, stream, separator = "", callbackFn) { let tail = false; do { let [trieI, childKey, childPtr] = stack[top]; - if (childKey >= TRIE_TAIL_NODE_CHILDREN_NUM) { + if (childKey >= TRIE_TAIL_NODE_CHILDREN_LEN) { --top; continue; } ++stack[top][1]; - stack[top][2] += TRIE_CHILD_LEN; + stack[top][2] += TRIE_CHILD_UTS; if (childKey === 0) { const nodeIndex = childPtr - TRIE_NODE_CHILDREN_IDX; const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX]; diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs.map b/src/main/nodejs/havelessbemore/dist/index.cjs.map index deb37fd..9e4e201 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.cjs.map @@ -1 +1 @@ -{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","// Trie static properties\n\nimport { UTF8_B0_2B_LEN, UTF8_BN_LEN } from \"./utf8\";\n\n/**\n * Represents null / undefined.\n */\nexport const TRIE_NULL = 0;\n\n/**\n * The minimum size a trie.\n */\nexport const MIN_TRIE_SIZE = 524288; // 2 MiB\n\n/**\n * The default growth factor for growing the size of a trie.\n */\nexport const TRIE_GROWTH_FACTOR = 1.618; // ~phi\n\n/**\n * All trie properties are represented by 32 bits (4 bytes).\n */\nexport const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT;\n\nexport const TRIE_BODY_NODE_CHILDREN_NUM = UTF8_BN_LEN;\nexport const TRIE_TAIL_NODE_CHILDREN_NUM = UTF8_B0_2B_LEN;\n\n// Trie child pointer properties\n\nexport const TRIE_CHILD_IDX_IDX = 0;\nexport const TRIE_CHILD_IDX_LEN = 1;\n\nexport const TRIE_CHILD_LEN = TRIE_CHILD_IDX_LEN;\n\n// Trie redirect pointer properties\n\nexport const TRIE_RED_ID_IDX = 0;\nexport const TRIE_RED_ID_LEN = 1;\n\nexport const TRIE_RED_VALUE_IDX_IDX = 1;\nexport const TRIE_RED_VALUE_IDX_LEN = 1;\n\nexport const TRIE_RED_LEN = TRIE_RED_ID_LEN + TRIE_RED_VALUE_IDX_LEN;\n\n// Trie node properties\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_LEN = 1;\n\nexport const TRIE_NODE_VALUE_IDX_IDX = 1;\nexport const TRIE_NODE_VALUE_IDX_LEN = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_BODY_NODE_CHILDREN_LEN =\n TRIE_CHILD_LEN * TRIE_BODY_NODE_CHILDREN_NUM;\nexport const TRIE_TAIL_NODE_CHILDREN_LEN =\n TRIE_CHILD_LEN * TRIE_TAIL_NODE_CHILDREN_NUM;\n\nexport const TRIE_BODY_NODE_LEN =\n TRIE_NODE_ID_LEN + TRIE_NODE_VALUE_IDX_LEN + TRIE_BODY_NODE_CHILDREN_LEN;\n\nexport const TRIE_TAIL_NODE_LEN =\n TRIE_NODE_ID_LEN + TRIE_NODE_VALUE_IDX_LEN + TRIE_TAIL_NODE_CHILDREN_LEN;\n\n// Trie properties\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_LEN = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_LEN = TRIE_TAIL_NODE_LEN;\n\nexport const TRIE_HEADER_LEN = TRIE_SIZE_LEN + TRIE_ROOT_LEN;\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n MIN_TRIE_SIZE,\n TRIE_CHILD_LEN,\n TRIE_CHILD_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_HEADER_LEN,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_RED_LEN,\n TRIE_RED_VALUE_IDX_IDX,\n TRIE_RED_ID_IDX,\n TRIE_TAIL_NODE_CHILDREN_NUM,\n TRIE_TAIL_NODE_CHILDREN_LEN,\n TRIE_TAIL_NODE_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_LEN * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_CHILD_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_TAIL_NODE_LEN > trie.length) {\n trie = grow(trie, child + TRIE_TAIL_NODE_LEN);\n }\n trie[TRIE_SIZE_IDX] += TRIE_TAIL_NODE_LEN;\n // Attach and initialize node\n trie[index + TRIE_CHILD_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array {\n const minSize = TRIE_HEADER_LEN;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n console.log(\"D\");\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_TAIL_NODE_CHILDREN_LEN;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_CHILD_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_RED_LEN > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_RED_LEN);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_RED_LEN;\n // Add new redirect\n tries[at][li + TRIE_RED_ID_IDX] = rt;\n tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, 0, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childKey, childPtr] = stack[top];\n\n // Check if end of children array\n if (childKey >= TRIE_TAIL_NODE_CHILDREN_NUM) {\n --top;\n continue;\n }\n\n // Update stack top\n ++stack[top][1];\n stack[top][2] += TRIE_CHILD_LEN;\n\n // If just reached node\n if (childKey === 0) {\n // Check if the node has a value\n const nodeIndex = childPtr - TRIE_NODE_CHILDREN_IDX;\n const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print the node's value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n }\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX];\n if (childI !== TRIE_NULL) {\n // Resolve child if redirect\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX];\n trieI = childTrieI;\n }\n // Add the child to the stack\n key[top] = childKey + UTF8_B0_MIN;\n stack[++top] = [trieI, 0, childI + TRIE_NODE_CHILDREN_IDX];\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/utf8Trie\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const numVals = MAX_STATIONS * maxWorkers + 1;\n let bpe = Uint32Array.BYTES_PER_ELEMENT;\n const counts = new Uint32Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Int16Array.BYTES_PER_ELEMENT;\n const maxes = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n const mins = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Float64Array.BYTES_PER_ELEMENT;\n const sums = new Float64Array(new SharedArrayBuffer(bpe * numVals));\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n counts,\n end,\n filePath,\n id,\n maxes,\n mins,\n start,\n sums,\n } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n tries[res.id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 1; i < maxWorkers; ++i) {\n mergeLeft(tries, 0, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(ai: number, bi: number): void {\n counts[ai] += counts[bi];\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n mins[ai] = Math.min(mins[ai], mins[bi]);\n sums[ai] += sums[bi];\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi] / counts[vi]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: WorkerRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n counts[index] = 1;\n maxes[index] = temp;\n mins[index] = temp;\n sums[index] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n ++counts[index];\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n sums[index] += temp;\n }\n\n return { id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n return ++min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [res.trie.buffer]);\n });\n}\n"],"names":["open","at","bt","run","Worker","createWriteStream","createReadStream","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN, UTF8_BN_LEN } from \"./utf8\";\n\n// Trie static properties\n\n/**\n * Represents null / undefined.\n */\nexport const TRIE_NULL = 0;\n\n/**\n * The minimum size a trie.\n */\nexport const MIN_TRIE_SIZE = 524288; // 2 MiB\n\n/**\n * The default growth factor for growing the size of a trie.\n */\nexport const TRIE_GROWTH_FACTOR = 1.618; // ~phi\n\n/**\n * All trie properties are represented by 32 bits (4 bytes).\n */\nexport const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT;\n\nexport const TRIE_BODY_NODE_CHILDREN_LEN = UTF8_BN_LEN;\nexport const TRIE_TAIL_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\n\n// Trie child pointer properties\n\nexport const TRIE_CHILD_IDX_IDX = 0;\nexport const TRIE_CHILD_IDX_UTS = 1;\n\nexport const TRIE_CHILD_UTS = TRIE_CHILD_IDX_UTS;\n\n// Trie redirect pointer properties\n\nexport const TRIE_RED_ID_IDX = 0;\nexport const TRIE_RED_ID_UTS = 1;\n\nexport const TRIE_RED_VALUE_IDX_IDX = 1;\nexport const TRIE_RED_VALUE_IDX_UTS = 1;\n\nexport const TRIE_RED_UTS = TRIE_RED_ID_UTS + TRIE_RED_VALUE_IDX_UTS;\n\n// Trie node properties\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_UTS = 1;\n\nexport const TRIE_NODE_VALUE_IDX_IDX = 1;\nexport const TRIE_NODE_VALUE_IDX_UTS = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_BODY_NODE_CHILDREN_UTS =\n TRIE_CHILD_UTS * TRIE_BODY_NODE_CHILDREN_LEN;\nexport const TRIE_TAIL_NODE_CHILDREN_UTS =\n TRIE_CHILD_UTS * TRIE_TAIL_NODE_CHILDREN_LEN;\n\nexport const TRIE_BODY_NODE_UTS =\n TRIE_NODE_ID_UTS + TRIE_NODE_VALUE_IDX_UTS + TRIE_BODY_NODE_CHILDREN_UTS;\n\nexport const TRIE_TAIL_NODE_UTS =\n TRIE_NODE_ID_UTS + TRIE_NODE_VALUE_IDX_UTS + TRIE_TAIL_NODE_CHILDREN_UTS;\n\n// Trie properties\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_UTS = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_UTS = TRIE_TAIL_NODE_UTS;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_HEADER_UTS = TRIE_SIZE_UTS + TRIE_ROOT_UTS;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n MIN_TRIE_SIZE,\n TRIE_CHILD_UTS,\n TRIE_CHILD_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_HEADER_UTS,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_RED_UTS,\n TRIE_RED_VALUE_IDX_IDX,\n TRIE_RED_ID_IDX,\n TRIE_TAIL_NODE_CHILDREN_LEN,\n TRIE_TAIL_NODE_CHILDREN_UTS,\n TRIE_TAIL_NODE_UTS,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_UTS * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_CHILD_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_TAIL_NODE_UTS > trie.length) {\n trie = grow(trie, child + TRIE_TAIL_NODE_UTS);\n }\n trie[TRIE_SIZE_IDX] += TRIE_TAIL_NODE_UTS;\n // Attach and initialize node\n trie[index + TRIE_CHILD_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array {\n const minSize = TRIE_HEADER_UTS;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n console.log(\"D\");\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_TAIL_NODE_CHILDREN_UTS;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_CHILD_UTS;\n bi += TRIE_CHILD_UTS;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_CHILD_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_RED_UTS > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_RED_UTS);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_RED_UTS;\n // Add new redirect\n tries[at][li + TRIE_RED_ID_IDX] = rt;\n tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_CHILD_UTS;\n bi += TRIE_CHILD_UTS;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, 0, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childKey, childPtr] = stack[top];\n\n // Check if end of children array\n if (childKey >= TRIE_TAIL_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n ++stack[top][1];\n stack[top][2] += TRIE_CHILD_UTS;\n\n // If just reached node\n if (childKey === 0) {\n // Check if the node has a value\n const nodeIndex = childPtr - TRIE_NODE_CHILDREN_IDX;\n const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print the node's value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n }\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX];\n if (childI !== TRIE_NULL) {\n // Resolve child if redirect\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX];\n trieI = childTrieI;\n }\n // Add the child to the stack\n key[top] = childKey + UTF8_B0_MIN;\n stack[++top] = [trieI, 0, childI + TRIE_NODE_CHILDREN_IDX];\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/utf8Trie\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const numVals = MAX_STATIONS * maxWorkers + 1;\n let bpe = Uint32Array.BYTES_PER_ELEMENT;\n const counts = new Uint32Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Int16Array.BYTES_PER_ELEMENT;\n const maxes = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n const mins = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Float64Array.BYTES_PER_ELEMENT;\n const sums = new Float64Array(new SharedArrayBuffer(bpe * numVals));\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n counts,\n end,\n filePath,\n id,\n maxes,\n mins,\n start,\n sums,\n } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n tries[res.id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 1; i < maxWorkers; ++i) {\n mergeLeft(tries, 0, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(ai: number, bi: number): void {\n counts[ai] += counts[bi];\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n mins[ai] = Math.min(mins[ai], mins[bi]);\n sums[ai] += sums[bi];\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi] / counts[vi]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: WorkerRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n counts[index] = 1;\n maxes[index] = temp;\n mins[index] = temp;\n sums[index] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n ++counts[index];\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n sums[index] += temp;\n }\n\n return { id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n return ++min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [res.trie.buffer]);\n });\n}\n"],"names":["open","at","bt","run","Worker","createWriteStream","createReadStream","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index 8d9e899..b8cc44f 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -65,40 +65,40 @@ function getHighWaterMark(size) { const TRIE_NULL = 0; const MIN_TRIE_SIZE = 524288; const TRIE_GROWTH_FACTOR = 1.618; -const TRIE_TAIL_NODE_CHILDREN_NUM = UTF8_B0_2B_LEN; +const TRIE_TAIL_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN; const TRIE_CHILD_IDX_IDX = 0; -const TRIE_CHILD_IDX_LEN = 1; -const TRIE_CHILD_LEN = TRIE_CHILD_IDX_LEN; +const TRIE_CHILD_IDX_UTS = 1; +const TRIE_CHILD_UTS = TRIE_CHILD_IDX_UTS; const TRIE_RED_ID_IDX = 0; -const TRIE_RED_ID_LEN = 1; +const TRIE_RED_ID_UTS = 1; const TRIE_RED_VALUE_IDX_IDX = 1; -const TRIE_RED_VALUE_IDX_LEN = 1; -const TRIE_RED_LEN = TRIE_RED_ID_LEN + TRIE_RED_VALUE_IDX_LEN; +const TRIE_RED_VALUE_IDX_UTS = 1; +const TRIE_RED_UTS = TRIE_RED_ID_UTS + TRIE_RED_VALUE_IDX_UTS; const TRIE_NODE_ID_IDX = 0; -const TRIE_NODE_ID_LEN = 1; +const TRIE_NODE_ID_UTS = 1; const TRIE_NODE_VALUE_IDX_IDX = 1; -const TRIE_NODE_VALUE_IDX_LEN = 1; +const TRIE_NODE_VALUE_IDX_UTS = 1; const TRIE_NODE_CHILDREN_IDX = 2; -const TRIE_TAIL_NODE_CHILDREN_LEN = TRIE_CHILD_LEN * TRIE_TAIL_NODE_CHILDREN_NUM; -const TRIE_TAIL_NODE_LEN = TRIE_NODE_ID_LEN + TRIE_NODE_VALUE_IDX_LEN + TRIE_TAIL_NODE_CHILDREN_LEN; +const TRIE_TAIL_NODE_CHILDREN_UTS = TRIE_CHILD_UTS * TRIE_TAIL_NODE_CHILDREN_LEN; +const TRIE_TAIL_NODE_UTS = TRIE_NODE_ID_UTS + TRIE_NODE_VALUE_IDX_UTS + TRIE_TAIL_NODE_CHILDREN_UTS; const TRIE_SIZE_IDX = 0; -const TRIE_SIZE_LEN = 1; +const TRIE_SIZE_UTS = 1; const TRIE_ROOT_IDX = 1; -const TRIE_ROOT_LEN = TRIE_TAIL_NODE_LEN; -const TRIE_HEADER_LEN = TRIE_SIZE_LEN + TRIE_ROOT_LEN; +const TRIE_ROOT_UTS = TRIE_TAIL_NODE_UTS; const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX; +const TRIE_HEADER_UTS = TRIE_SIZE_UTS + TRIE_ROOT_UTS; function add(trie, key, min, max) { let index = TRIE_ROOT_IDX; while (min < max) { - index += TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_LEN * (key[min++] - UTF8_B0_MIN); + index += TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_UTS * (key[min++] - UTF8_B0_MIN); let child = trie[index + TRIE_CHILD_IDX_IDX]; if (child === TRIE_NULL) { child = trie[TRIE_SIZE_IDX]; - if (child + TRIE_TAIL_NODE_LEN > trie.length) { - trie = grow(trie, child + TRIE_TAIL_NODE_LEN); + if (child + TRIE_TAIL_NODE_UTS > trie.length) { + trie = grow(trie, child + TRIE_TAIL_NODE_UTS); } - trie[TRIE_SIZE_IDX] += TRIE_TAIL_NODE_LEN; + trie[TRIE_SIZE_IDX] += TRIE_TAIL_NODE_UTS; trie[index + TRIE_CHILD_IDX_IDX] = child; trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX]; } @@ -107,7 +107,7 @@ function add(trie, key, min, max) { return [trie, index]; } function createTrie(id = 0, size = MIN_TRIE_SIZE) { - const minSize = TRIE_HEADER_LEN; + const minSize = TRIE_HEADER_UTS; const trie = new Int32Array(Math.max(minSize, size)); trie[TRIE_SIZE_IDX] = minSize; trie[TRIE_ID_IDX] = id; @@ -142,12 +142,12 @@ function mergeLeft(tries, at, bt, mergeFn) { } ai += TRIE_NODE_CHILDREN_IDX; bi += TRIE_NODE_CHILDREN_IDX; - const bn = bi + TRIE_TAIL_NODE_CHILDREN_LEN; + const bn = bi + TRIE_TAIL_NODE_CHILDREN_UTS; while (bi < bn) { let ri = tries[bt2][bi + TRIE_CHILD_IDX_IDX]; if (ri === TRIE_NULL) { - ai += TRIE_CHILD_LEN; - bi += TRIE_CHILD_LEN; + ai += TRIE_CHILD_UTS; + bi += TRIE_CHILD_UTS; continue; } const rt = tries[bt2][ri + TRIE_NODE_ID_IDX]; @@ -157,10 +157,10 @@ function mergeLeft(tries, at, bt, mergeFn) { let li = tries[at2][ai + TRIE_CHILD_IDX_IDX]; if (li === TRIE_NULL) { li = tries[at2][TRIE_SIZE_IDX]; - if (li + TRIE_RED_LEN > tries[at2].length) { - tries[at2] = grow(tries[at2], li + TRIE_RED_LEN); + if (li + TRIE_RED_UTS > tries[at2].length) { + tries[at2] = grow(tries[at2], li + TRIE_RED_UTS); } - tries[at2][TRIE_SIZE_IDX] += TRIE_RED_LEN; + tries[at2][TRIE_SIZE_IDX] += TRIE_RED_UTS; tries[at2][li + TRIE_RED_ID_IDX] = rt; tries[at2][li + TRIE_RED_VALUE_IDX_IDX] = ri; } else { @@ -170,8 +170,8 @@ function mergeLeft(tries, at, bt, mergeFn) { } queue.push([lt, li, rt, ri]); } - ai += TRIE_CHILD_LEN; - bi += TRIE_CHILD_LEN; + ai += TRIE_CHILD_UTS; + bi += TRIE_CHILD_UTS; } } queue.splice(0, Q); @@ -184,12 +184,12 @@ function print(tries, key, trieIndex, stream, separator = "", callbackFn) { let tail = false; do { let [trieI, childKey, childPtr] = stack[top]; - if (childKey >= TRIE_TAIL_NODE_CHILDREN_NUM) { + if (childKey >= TRIE_TAIL_NODE_CHILDREN_LEN) { --top; continue; } ++stack[top][1]; - stack[top][2] += TRIE_CHILD_LEN; + stack[top][2] += TRIE_CHILD_UTS; if (childKey === 0) { const nodeIndex = childPtr - TRIE_NODE_CHILDREN_IDX; const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX]; diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index e1665d8..13f7426 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1 +1 @@ -{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","// Trie static properties\n\nimport { UTF8_B0_2B_LEN, UTF8_BN_LEN } from \"./utf8\";\n\n/**\n * Represents null / undefined.\n */\nexport const TRIE_NULL = 0;\n\n/**\n * The minimum size a trie.\n */\nexport const MIN_TRIE_SIZE = 524288; // 2 MiB\n\n/**\n * The default growth factor for growing the size of a trie.\n */\nexport const TRIE_GROWTH_FACTOR = 1.618; // ~phi\n\n/**\n * All trie properties are represented by 32 bits (4 bytes).\n */\nexport const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT;\n\nexport const TRIE_BODY_NODE_CHILDREN_NUM = UTF8_BN_LEN;\nexport const TRIE_TAIL_NODE_CHILDREN_NUM = UTF8_B0_2B_LEN;\n\n// Trie child pointer properties\n\nexport const TRIE_CHILD_IDX_IDX = 0;\nexport const TRIE_CHILD_IDX_LEN = 1;\n\nexport const TRIE_CHILD_LEN = TRIE_CHILD_IDX_LEN;\n\n// Trie redirect pointer properties\n\nexport const TRIE_RED_ID_IDX = 0;\nexport const TRIE_RED_ID_LEN = 1;\n\nexport const TRIE_RED_VALUE_IDX_IDX = 1;\nexport const TRIE_RED_VALUE_IDX_LEN = 1;\n\nexport const TRIE_RED_LEN = TRIE_RED_ID_LEN + TRIE_RED_VALUE_IDX_LEN;\n\n// Trie node properties\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_LEN = 1;\n\nexport const TRIE_NODE_VALUE_IDX_IDX = 1;\nexport const TRIE_NODE_VALUE_IDX_LEN = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_BODY_NODE_CHILDREN_LEN =\n TRIE_CHILD_LEN * TRIE_BODY_NODE_CHILDREN_NUM;\nexport const TRIE_TAIL_NODE_CHILDREN_LEN =\n TRIE_CHILD_LEN * TRIE_TAIL_NODE_CHILDREN_NUM;\n\nexport const TRIE_BODY_NODE_LEN =\n TRIE_NODE_ID_LEN + TRIE_NODE_VALUE_IDX_LEN + TRIE_BODY_NODE_CHILDREN_LEN;\n\nexport const TRIE_TAIL_NODE_LEN =\n TRIE_NODE_ID_LEN + TRIE_NODE_VALUE_IDX_LEN + TRIE_TAIL_NODE_CHILDREN_LEN;\n\n// Trie properties\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_LEN = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_LEN = TRIE_TAIL_NODE_LEN;\n\nexport const TRIE_HEADER_LEN = TRIE_SIZE_LEN + TRIE_ROOT_LEN;\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n MIN_TRIE_SIZE,\n TRIE_CHILD_LEN,\n TRIE_CHILD_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_HEADER_LEN,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_RED_LEN,\n TRIE_RED_VALUE_IDX_IDX,\n TRIE_RED_ID_IDX,\n TRIE_TAIL_NODE_CHILDREN_NUM,\n TRIE_TAIL_NODE_CHILDREN_LEN,\n TRIE_TAIL_NODE_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_LEN * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_CHILD_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_TAIL_NODE_LEN > trie.length) {\n trie = grow(trie, child + TRIE_TAIL_NODE_LEN);\n }\n trie[TRIE_SIZE_IDX] += TRIE_TAIL_NODE_LEN;\n // Attach and initialize node\n trie[index + TRIE_CHILD_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array {\n const minSize = TRIE_HEADER_LEN;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n console.log(\"D\");\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_TAIL_NODE_CHILDREN_LEN;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_CHILD_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_RED_LEN > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_RED_LEN);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_RED_LEN;\n // Add new redirect\n tries[at][li + TRIE_RED_ID_IDX] = rt;\n tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_CHILD_LEN;\n bi += TRIE_CHILD_LEN;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, 0, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childKey, childPtr] = stack[top];\n\n // Check if end of children array\n if (childKey >= TRIE_TAIL_NODE_CHILDREN_NUM) {\n --top;\n continue;\n }\n\n // Update stack top\n ++stack[top][1];\n stack[top][2] += TRIE_CHILD_LEN;\n\n // If just reached node\n if (childKey === 0) {\n // Check if the node has a value\n const nodeIndex = childPtr - TRIE_NODE_CHILDREN_IDX;\n const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print the node's value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n }\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX];\n if (childI !== TRIE_NULL) {\n // Resolve child if redirect\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX];\n trieI = childTrieI;\n }\n // Add the child to the stack\n key[top] = childKey + UTF8_B0_MIN;\n stack[++top] = [trieI, 0, childI + TRIE_NODE_CHILDREN_IDX];\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/utf8Trie\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const numVals = MAX_STATIONS * maxWorkers + 1;\n let bpe = Uint32Array.BYTES_PER_ELEMENT;\n const counts = new Uint32Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Int16Array.BYTES_PER_ELEMENT;\n const maxes = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n const mins = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Float64Array.BYTES_PER_ELEMENT;\n const sums = new Float64Array(new SharedArrayBuffer(bpe * numVals));\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n counts,\n end,\n filePath,\n id,\n maxes,\n mins,\n start,\n sums,\n } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n tries[res.id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 1; i < maxWorkers; ++i) {\n mergeLeft(tries, 0, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(ai: number, bi: number): void {\n counts[ai] += counts[bi];\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n mins[ai] = Math.min(mins[ai], mins[bi]);\n sums[ai] += sums[bi];\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi] / counts[vi]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: WorkerRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n counts[index] = 1;\n maxes[index] = temp;\n mins[index] = temp;\n sums[index] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n ++counts[index];\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n sums[index] += temp;\n }\n\n return { id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n return ++min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [res.trie.buffer]);\n });\n}\n"],"names":["at","bt","run","runMain","runWorker"],"mappings":";;;;;;AAQO,MAAM,YAAe,GAAA,GAAA,CAAA;AAKrB,MAAM,oBAAuB,GAAA,GAAA,CAAA;AAW7B,MAAM,aAAgB,GAAA,GAAA;;ACnBtB,MAAM,UAAa,GAAA,EAAA,CAAA;AAKnB,MAAM,YAAe,GAAA,EAAA,CAAA;AAUrB,MAAM,cAAiB,GAAA,EAAA,CAAA;AAKvB,MAAM,SAAY,GAAA,EAAA,CAAA;AAWlB,MAAM,WAAc,GAAA,EAAA,CAAA;AAuBpB,MAAM,cAAiB,GAAA,GAAA,CAAA;AAMjB,MAAA,cAAA,GAAiB,iBAAiB,WAAc,GAAA,CAAA;;AC5DtD,MAAM,mBAAsB,GAAA,KAAA,CAAA;AAK5B,MAAM,mBAAsB,GAAA,OAAA,CAAA;AAK5B,MAAM,mBAAsB,GAAA,OAAA,CAAA;AAM5B,MAAM,qBAAwB,GAAA,MAAA,CAAA;AAK9B,MAAM,cAAiB,GAAA,mBAAA,CAAA;AAOvB,MAAM,eAAe,EAAK,GAAA,SAAA,CAAA;AAK1B,MAAM,gBAAgB,GAAM,GAAA,SAAA;;ACnC5B,MAAM,WAAc,GAAA,CAAA,CAAA;AAKpB,MAAM,WAAc,GAAA,GAAA;;ACUX,SAAA,KAAA,CAAM,KAAe,EAAA,GAAA,EAAa,GAAqB,EAAA;AACrE,EAAA,OAAO,KAAQ,GAAA,GAAA,GAAO,KAAS,IAAA,GAAA,GAAM,QAAQ,GAAO,GAAA,GAAA,CAAA;AACtD,CAAA;AAoBA,eAAsB,aACpB,CAAA,QAAA,EACA,MACA,EAAA,aAAA,EACA,UAAU,CACmB,EAAA;AAE7B,EAAM,MAAA,IAAA,GAAO,MAAM,IAAA,CAAK,QAAQ,CAAA,CAAA;AAChC,EAAI,IAAA;AAEF,IAAA,MAAM,IAAQ,GAAA,CAAA,MAAM,IAAK,CAAA,IAAA,EAAQ,EAAA,IAAA,CAAA;AAEjC,IAAM,MAAA,SAAA,GAAY,KAAK,GAAI,CAAA,OAAA,EAAS,KAAK,KAAM,CAAA,IAAA,GAAO,MAAM,CAAC,CAAA,CAAA;AAE7D,IAAM,MAAA,MAAA,GAAS,MAAO,CAAA,WAAA,CAAY,aAAa,CAAA,CAAA;AAC/C,IAAA,MAAM,SAA6B,EAAC,CAAA;AAEpC,IAAA,IAAI,KAAQ,GAAA,CAAA,CAAA;AACZ,IAAA,KAAA,IAAS,GAAM,GAAA,SAAA,EAAW,GAAM,GAAA,IAAA,EAAM,OAAO,SAAW,EAAA;AAEtD,MAAA,MAAM,MAAM,MAAM,IAAA,CAAK,KAAK,MAAQ,EAAA,CAAA,EAAG,eAAe,GAAG,CAAA,CAAA;AAEzD,MAAM,MAAA,OAAA,GAAU,MAAO,CAAA,OAAA,CAAQ,YAAY,CAAA,CAAA;AAE3C,MAAA,IAAI,OAAW,IAAA,CAAA,IAAK,OAAU,GAAA,GAAA,CAAI,SAAW,EAAA;AAE3C,QAAA,GAAA,IAAO,OAAU,GAAA,CAAA,CAAA;AAEjB,QAAA,MAAA,CAAO,IAAK,CAAA,CAAC,KAAO,EAAA,GAAG,CAAC,CAAA,CAAA;AAExB,QAAQ,KAAA,GAAA,GAAA,CAAA;AAAA,OACV;AAAA,KACF;AAEA,IAAA,IAAI,QAAQ,IAAM,EAAA;AAChB,MAAA,MAAA,CAAO,IAAK,CAAA,CAAC,KAAO,EAAA,IAAI,CAAC,CAAA,CAAA;AAAA,KAC3B;AAEA,IAAO,OAAA,MAAA,CAAA;AAAA,GACP,SAAA;AAEA,IAAA,MAAM,KAAK,KAAM,EAAA,CAAA;AAAA,GACnB;AACF,CAAA;AASO,SAAS,iBAAiB,IAAsB,EAAA;AAErD,EAAQ,IAAA,IAAA,qBAAA,CAAA;AAER,EAAA,IAAA,GAAO,IAAK,CAAA,KAAA,CAAM,IAAK,CAAA,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA;AAEjC,EAAA,IAAA,GAAO,CAAK,IAAA,IAAA,CAAA;AAEZ,EAAO,OAAA,KAAA,CAAM,IAAM,EAAA,mBAAA,EAAqB,mBAAmB,CAAA,CAAA;AAC7D;;AC9FO,MAAM,SAAY,GAAA,CAAA,CAAA;AAKlB,MAAM,aAAgB,GAAA,MAAA,CAAA;AAKtB,MAAM,kBAAqB,GAAA,KAAA,CAAA;AAQ3B,MAAM,2BAA8B,GAAA,cAAA,CAAA;AAIpC,MAAM,kBAAqB,GAAA,CAAA,CAAA;AAC3B,MAAM,kBAAqB,GAAA,CAAA,CAAA;AAE3B,MAAM,cAAiB,GAAA,kBAAA,CAAA;AAIvB,MAAM,eAAkB,GAAA,CAAA,CAAA;AACxB,MAAM,eAAkB,GAAA,CAAA,CAAA;AAExB,MAAM,sBAAyB,GAAA,CAAA,CAAA;AAC/B,MAAM,sBAAyB,GAAA,CAAA,CAAA;AAE/B,MAAM,eAAe,eAAkB,GAAA,sBAAA,CAAA;AAIvC,MAAM,gBAAmB,GAAA,CAAA,CAAA;AACzB,MAAM,gBAAmB,GAAA,CAAA,CAAA;AAEzB,MAAM,uBAA0B,GAAA,CAAA,CAAA;AAChC,MAAM,uBAA0B,GAAA,CAAA,CAAA;AAEhC,MAAM,sBAAyB,GAAA,CAAA,CAAA;AAG/B,MAAM,8BACX,cAAiB,GAAA,2BAAA,CAAA;AAKN,MAAA,kBAAA,GACX,mBAAmB,uBAA0B,GAAA,2BAAA,CAAA;AAIxC,MAAM,aAAgB,GAAA,CAAA,CAAA;AACtB,MAAM,aAAgB,GAAA,CAAA,CAAA;AAEtB,MAAM,aAAgB,GAAA,CAAA,CAAA;AACtB,MAAM,aAAgB,GAAA,kBAAA,CAAA;AAEtB,MAAM,kBAAkB,aAAgB,GAAA,aAAA,CAAA;AACxC,MAAM,cAAc,aAAgB,GAAA,gBAAA;;ACjDpC,SAAS,GACd,CAAA,IAAA,EACA,GACA,EAAA,GAAA,EACA,GACsB,EAAA;AACtB,EAAA,IAAI,KAAQ,GAAA,aAAA,CAAA;AACZ,EAAA,OAAO,MAAM,GAAK,EAAA;AAChB,IAAA,KAAA,IACE,sBAAyB,GAAA,cAAA,IAAkB,GAAI,CAAA,GAAA,EAAK,CAAI,GAAA,WAAA,CAAA,CAAA;AAC1D,IAAI,IAAA,KAAA,GAAQ,IAAK,CAAA,KAAA,GAAQ,kBAAkB,CAAA,CAAA;AAC3C,IAAA,IAAI,UAAU,SAAW,EAAA;AAEvB,MAAA,KAAA,GAAQ,KAAK,aAAa,CAAA,CAAA;AAC1B,MAAI,IAAA,KAAA,GAAQ,kBAAqB,GAAA,IAAA,CAAK,MAAQ,EAAA;AAC5C,QAAO,IAAA,GAAA,IAAA,CAAK,IAAM,EAAA,KAAA,GAAQ,kBAAkB,CAAA,CAAA;AAAA,OAC9C;AACA,MAAA,IAAA,CAAK,aAAa,CAAK,IAAA,kBAAA,CAAA;AAEvB,MAAK,IAAA,CAAA,KAAA,GAAQ,kBAAkB,CAAI,GAAA,KAAA,CAAA;AACnC,MAAA,IAAA,CAAK,KAAQ,GAAA,gBAAgB,CAAI,GAAA,IAAA,CAAK,WAAW,CAAA,CAAA;AAAA,KACnD;AACA,IAAQ,KAAA,GAAA,KAAA,CAAA;AAAA,GACV;AAEA,EAAO,OAAA,CAAC,MAAM,KAAK,CAAA,CAAA;AACrB,CAAA;AAEO,SAAS,UAAW,CAAA,EAAA,GAAK,CAAG,EAAA,IAAA,GAAO,aAA2B,EAAA;AACnE,EAAA,MAAM,OAAU,GAAA,eAAA,CAAA;AAChB,EAAA,MAAM,OAAO,IAAI,UAAA,CAAW,KAAK,GAAI,CAAA,OAAA,EAAS,IAAI,CAAC,CAAA,CAAA;AACnD,EAAA,IAAA,CAAK,aAAa,CAAI,GAAA,OAAA,CAAA;AACtB,EAAA,IAAA,CAAK,WAAW,CAAI,GAAA,EAAA,CAAA;AACpB,EAAO,OAAA,IAAA,CAAA;AACT,CAAA;AAEgB,SAAA,IAAA,CAAK,IAAkB,EAAA,OAAA,GAAU,CAAe,EAAA;AAC9D,EAAA,OAAA,CAAQ,IAAI,GAAG,CAAA,CAAA;AACf,EAAM,MAAA,MAAA,GAAS,KAAK,aAAa,CAAA,CAAA;AACjC,EAAA,OAAA,GAAU,KAAK,GAAI,CAAA,OAAA,EAAS,KAAK,IAAK,CAAA,MAAA,GAAS,kBAAkB,CAAC,CAAA,CAAA;AAClE,EAAM,MAAA,IAAA,GAAO,IAAI,UAAA,CAAW,OAAO,CAAA,CAAA;AACnC,EAAA,KAAA,IAAS,CAAI,GAAA,CAAA,EAAG,CAAI,GAAA,MAAA,EAAQ,EAAE,CAAG,EAAA;AAC/B,IAAK,IAAA,CAAA,CAAC,CAAI,GAAA,IAAA,CAAK,CAAC,CAAA,CAAA;AAAA,GAClB;AACA,EAAO,OAAA,IAAA,CAAA;AACT,CAAA;AAEO,SAAS,SACd,CAAA,KAAA,EACA,EACA,EAAA,EAAA,EACA,OACM,EAAA;AACN,EAAA,MAAM,KAA4C,GAAA;AAAA,IAChD,CAAC,EAAA,EAAI,aAAe,EAAA,EAAA,EAAI,aAAa,CAAA;AAAA,GACvC,CAAA;AAEA,EAAG,GAAA;AACD,IAAA,MAAM,IAAI,KAAM,CAAA,MAAA,CAAA;AAChB,IAAA,KAAA,IAAS,CAAI,GAAA,CAAA,EAAG,CAAI,GAAA,CAAA,EAAG,EAAE,CAAG,EAAA;AAC1B,MAAA,IAAI,CAACA,GAAI,EAAA,EAAA,EAAIC,KAAI,EAAE,CAAA,GAAI,MAAM,CAAC,CAAA,CAAA;AAG9B,MAAA,MAAM,GAAM,GAAA,KAAA,CAAMA,GAAE,CAAA,CAAE,KAAK,uBAAuB,CAAA,CAAA;AAClD,MAAA,IAAI,QAAQ,SAAW,EAAA;AAErB,QAAA,MAAM,GAAM,GAAA,KAAA,CAAMD,GAAE,CAAA,CAAE,KAAK,uBAAuB,CAAA,CAAA;AAClD,QAAA,IAAI,QAAQ,SAAW,EAAA;AACrB,UAAA,OAAA,CAAQ,KAAK,GAAG,CAAA,CAAA;AAAA,SACX,MAAA;AACL,UAAA,KAAA,CAAMA,GAAE,CAAA,CAAE,EAAK,GAAA,uBAAuB,CAAI,GAAA,GAAA,CAAA;AAAA,SAC5C;AAAA,OACF;AAGA,MAAM,EAAA,IAAA,sBAAA,CAAA;AACN,MAAM,EAAA,IAAA,sBAAA,CAAA;AAGN,MAAA,MAAM,KAAK,EAAK,GAAA,2BAAA,CAAA;AAChB,MAAA,OAAO,KAAK,EAAI,EAAA;AAEd,QAAA,IAAI,EAAK,GAAA,KAAA,CAAMC,GAAE,CAAA,CAAE,KAAK,kBAAkB,CAAA,CAAA;AAC1C,QAAA,IAAI,OAAO,SAAW,EAAA;AAEpB,UAAM,EAAA,IAAA,cAAA,CAAA;AACN,UAAM,EAAA,IAAA,cAAA,CAAA;AACN,UAAA,SAAA;AAAA,SACF;AAGA,QAAA,MAAM,EAAK,GAAA,KAAA,CAAMA,GAAE,CAAA,CAAE,KAAK,gBAAgB,CAAA,CAAA;AAC1C,QAAA,IAAIA,QAAO,EAAI,EAAA;AACb,UAAA,EAAA,GAAK,KAAMA,CAAAA,GAAE,CAAE,CAAA,EAAA,GAAK,sBAAsB,CAAA,CAAA;AAAA,SAC5C;AAGA,QAAA,IAAI,EAAK,GAAA,KAAA,CAAMD,GAAE,CAAA,CAAE,KAAK,kBAAkB,CAAA,CAAA;AAC1C,QAAA,IAAI,OAAO,SAAW,EAAA;AAEpB,UAAK,EAAA,GAAA,KAAA,CAAMA,GAAE,CAAA,CAAE,aAAa,CAAA,CAAA;AAC5B,UAAA,IAAI,EAAK,GAAA,YAAA,GAAe,KAAMA,CAAAA,GAAE,EAAE,MAAQ,EAAA;AACxC,YAAA,KAAA,CAAMA,GAAE,CAAI,GAAA,IAAA,CAAK,MAAMA,GAAE,CAAA,EAAG,KAAK,YAAY,CAAA,CAAA;AAAA,WAC/C;AACA,UAAMA,KAAAA,CAAAA,GAAE,CAAE,CAAA,aAAa,CAAK,IAAA,YAAA,CAAA;AAE5B,UAAA,KAAA,CAAMA,GAAE,CAAA,CAAE,EAAK,GAAA,eAAe,CAAI,GAAA,EAAA,CAAA;AAClC,UAAA,KAAA,CAAMA,GAAE,CAAA,CAAE,EAAK,GAAA,sBAAsB,CAAI,GAAA,EAAA,CAAA;AAAA,SACpC,MAAA;AAEL,UAAA,MAAM,EAAK,GAAA,KAAA,CAAMA,GAAE,CAAA,CAAE,KAAK,gBAAgB,CAAA,CAAA;AAC1C,UAAA,IAAIA,QAAO,EAAI,EAAA;AACb,YAAA,EAAA,GAAK,KAAMA,CAAAA,GAAE,CAAE,CAAA,EAAA,GAAK,sBAAsB,CAAA,CAAA;AAAA,WAC5C;AAEA,UAAA,KAAA,CAAM,KAAK,CAAC,EAAA,EAAI,EAAI,EAAA,EAAA,EAAI,EAAE,CAAC,CAAA,CAAA;AAAA,SAC7B;AAGA,QAAM,EAAA,IAAA,cAAA,CAAA;AACN,QAAM,EAAA,IAAA,cAAA,CAAA;AAAA,OACR;AAAA,KACF;AACA,IAAM,KAAA,CAAA,MAAA,CAAO,GAAG,CAAC,CAAA,CAAA;AAAA,GACnB,QAAS,MAAM,MAAS,GAAA,CAAA,EAAA;AAC1B,CAAA;AAEO,SAAS,MACd,KACA,EAAA,GAAA,EACA,WACA,MACA,EAAA,SAAA,GAAY,IACZ,UAMM,EAAA;AACN,EAAA,MAAM,KAAoC,GAAA,IAAI,KAAM,CAAA,GAAA,CAAI,SAAS,CAAC,CAAA,CAAA;AAClE,EAAA,KAAA,CAAM,CAAC,CAAI,GAAA,CAAC,SAAW,EAAA,CAAA,EAAG,gBAAgB,sBAAsB,CAAA,CAAA;AAEhE,EAAA,IAAI,GAAM,GAAA,CAAA,CAAA;AACV,EAAA,IAAI,IAAO,GAAA,KAAA,CAAA;AACX,EAAG,GAAA;AACD,IAAA,IAAI,CAAC,KAAO,EAAA,QAAA,EAAU,QAAQ,CAAA,GAAI,MAAM,GAAG,CAAA,CAAA;AAG3C,IAAA,IAAI,YAAY,2BAA6B,EAAA;AAC3C,MAAE,EAAA,GAAA,CAAA;AACF,MAAA,SAAA;AAAA,KACF;AAGA,IAAE,EAAA,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,CAAA,CAAA;AACd,IAAM,KAAA,CAAA,GAAG,CAAE,CAAA,CAAC,CAAK,IAAA,cAAA,CAAA;AAGjB,IAAA,IAAI,aAAa,CAAG,EAAA;AAElB,MAAA,MAAM,YAAY,QAAW,GAAA,sBAAA,CAAA;AAC7B,MAAA,MAAM,UAAa,GAAA,KAAA,CAAM,KAAK,CAAA,CAAE,YAAY,uBAAuB,CAAA,CAAA;AACnE,MAAA,IAAI,eAAe,SAAW,EAAA;AAE5B,QAAA,IAAI,IAAM,EAAA;AACR,UAAA,MAAA,CAAO,MAAM,SAAS,CAAA,CAAA;AAAA,SACxB;AACA,QAAO,IAAA,GAAA,IAAA,CAAA;AACP,QAAW,UAAA,CAAA,MAAA,EAAQ,GAAK,EAAA,GAAA,EAAK,UAAU,CAAA,CAAA;AAAA,OACzC;AAAA,KACF;AAGA,IAAA,IAAI,MAAS,GAAA,KAAA,CAAM,KAAK,CAAA,CAAE,WAAW,kBAAkB,CAAA,CAAA;AACvD,IAAA,IAAI,WAAW,SAAW,EAAA;AAExB,MAAA,MAAM,UAAa,GAAA,KAAA,CAAM,KAAK,CAAA,CAAE,SAAS,gBAAgB,CAAA,CAAA;AACzD,MAAA,IAAI,UAAU,UAAY,EAAA;AACxB,QAAA,MAAA,GAAS,KAAM,CAAA,KAAK,CAAE,CAAA,MAAA,GAAS,sBAAsB,CAAA,CAAA;AACrD,QAAQ,KAAA,GAAA,UAAA,CAAA;AAAA,OACV;AAEA,MAAI,GAAA,CAAA,GAAG,IAAI,QAAW,GAAA,WAAA,CAAA;AACtB,MAAA,KAAA,CAAM,EAAE,GAAG,CAAA,GAAI,CAAC,KAAO,EAAA,CAAA,EAAG,SAAS,sBAAsB,CAAA,CAAA;AAAA,KAC3D;AAAA,WACO,GAAO,IAAA,CAAA,EAAA;AAClB;;ACnMA,eAAsBE,KACpB,CAAA,QAAA,EACA,UACA,EAAA,UAAA,EACA,UAAU,EACK,EAAA;AAEf,EAAa,UAAA,GAAA,KAAA,CAAM,UAAY,EAAA,WAAA,EAAa,WAAW,CAAA,CAAA;AAGvD,EAAA,MAAM,SAAS,MAAM,aAAA;AAAA,IACnB,QAAA;AAAA,IACA,UAAA;AAAA,IACA,aAAA;AAAA,IACA,cAAA;AAAA,GACF,CAAA;AAGA,EAAA,UAAA,GAAa,MAAO,CAAA,MAAA,CAAA;AAGpB,EAAM,MAAA,OAAA,GAAU,eAAe,UAAa,GAAA,CAAA,CAAA;AAC5C,EAAA,IAAI,MAAM,WAAY,CAAA,iBAAA,CAAA;AACtB,EAAA,MAAM,SAAS,IAAI,WAAA,CAAY,IAAI,iBAAkB,CAAA,GAAA,GAAM,OAAO,CAAC,CAAA,CAAA;AACnE,EAAA,GAAA,GAAM,UAAW,CAAA,iBAAA,CAAA;AACjB,EAAA,MAAM,QAAQ,IAAI,UAAA,CAAW,IAAI,iBAAkB,CAAA,GAAA,GAAM,OAAO,CAAC,CAAA,CAAA;AACjE,EAAA,MAAM,OAAO,IAAI,UAAA,CAAW,IAAI,iBAAkB,CAAA,GAAA,GAAM,OAAO,CAAC,CAAA,CAAA;AAChE,EAAA,GAAA,GAAM,YAAa,CAAA,iBAAA,CAAA;AACnB,EAAA,MAAM,OAAO,IAAI,YAAA,CAAa,IAAI,iBAAkB,CAAA,GAAA,GAAM,OAAO,CAAC,CAAA,CAAA;AAClE,EAAM,MAAA,KAAA,GAAsB,IAAI,KAAA,CAAM,UAAU,CAAA,CAAA;AAGhD,EAAM,MAAA,OAAA,GAAU,IAAI,KAAA,CAAc,UAAU,CAAA,CAAA;AAC5C,EAAA,KAAA,IAAS,CAAI,GAAA,CAAA,EAAG,CAAI,GAAA,UAAA,EAAY,EAAE,CAAG,EAAA;AACnC,IAAM,MAAA,MAAA,GAAS,IAAI,MAAA,CAAO,UAAU,CAAA,CAAA;AACpC,IAAO,MAAA,CAAA,EAAA,CAAG,OAAS,EAAA,CAAC,GAAQ,KAAA;AAC1B,MAAM,MAAA,GAAA,CAAA;AAAA,KACP,CAAA,CAAA;AACD,IAAO,MAAA,CAAA,EAAA,CAAG,cAAgB,EAAA,CAAC,GAAQ,KAAA;AACjC,MAAM,MAAA,GAAA,CAAA;AAAA,KACP,CAAA,CAAA;AACD,IAAO,MAAA,CAAA,EAAA,CAAG,MAAQ,EAAA,CAAC,IAAS,KAAA;AAC1B,MAAI,IAAA,IAAA,GAAO,CAAK,IAAA,IAAA,GAAO,CAAG,EAAA;AACxB,QAAA,MAAM,IAAI,KAAM,CAAA,CAAA,OAAA,EAAU,OAAO,QAAQ,CAAA,kBAAA,EAAqB,IAAI,CAAE,CAAA,CAAA,CAAA;AAAA,OACtE;AAAA,KACD,CAAA,CAAA;AACD,IAAA,OAAA,CAAQ,CAAC,CAAI,GAAA,MAAA,CAAA;AAAA,GACf;AAGA,EAAM,MAAA,KAAA,GAAQ,IAAI,KAAA,CAA+B,UAAU,CAAA,CAAA;AAC3D,EAAA,KAAA,IAAS,CAAI,GAAA,CAAA,EAAG,CAAI,GAAA,UAAA,EAAY,EAAE,CAAG,EAAA;AACnC,IAAA,MAAM,EAAK,GAAA,CAAA,CAAA;AACX,IAAM,MAAA,MAAA,GAAS,QAAQ,CAAC,CAAA,CAAA;AACxB,IAAA,MAAM,CAAC,KAAA,EAAO,GAAG,CAAA,GAAI,OAAO,CAAC,CAAA,CAAA;AAC7B,IAAA,KAAA,CAAM,CAAC,CAAA,GAAI,IAAI,OAAA,CAAQ,CAAC,OAAY,KAAA;AAClC,MAAO,MAAA,CAAA,IAAA,CAAK,WAAW,OAAO,CAAA,CAAA;AAC9B,MAAA,MAAA,CAAO,WAAY,CAAA;AAAA,QACjB,MAAA;AAAA,QACA,GAAA;AAAA,QACA,QAAA;AAAA,QACA,EAAA;AAAA,QACA,KAAA;AAAA,QACA,IAAA;AAAA,QACA,KAAA;AAAA,QACA,IAAA;AAAA,OACgB,CAAA,CAAA;AAAA,KACnB,CAAA,CAAA;AAAA,GACH;AAGA,EAAA,WAAA,MAAiB,OAAO,KAAO,EAAA;AAC7B,IAAM,KAAA,CAAA,GAAA,CAAI,EAAE,CAAA,GAAI,GAAI,CAAA,IAAA,CAAA;AAAA,GACtB;AAGA,EAAA,KAAA,IAAS,CAAI,GAAA,CAAA,EAAG,CAAI,GAAA,UAAA,EAAY,EAAE,CAAG,EAAA;AACnC,IAAM,MAAA,OAAA,CAAQ,CAAC,CAAA,CAAE,SAAU,EAAA,CAAA;AAAA,GAC7B;AAGA,EAAA,KAAA,IAAS,CAAI,GAAA,CAAA,EAAG,CAAI,GAAA,UAAA,EAAY,EAAE,CAAG,EAAA;AACnC,IAAU,SAAA,CAAA,KAAA,EAAO,CAAG,EAAA,CAAA,EAAG,aAAa,CAAA,CAAA;AAAA,GACtC;AAGA,EAAM,MAAA,GAAA,GAAM,kBAAkB,OAAS,EAAA;AAAA,IACrC,EAAI,EAAA,OAAA,CAAQ,MAAS,GAAA,CAAA,GAAI,CAAI,GAAA,KAAA,CAAA;AAAA,IAC7B,KAAO,EAAA,GAAA;AAAA,IACP,aAAe,EAAA,mBAAA;AAAA,GAChB,CAAA,CAAA;AACD,EAAM,MAAA,MAAA,GAAS,MAAO,CAAA,WAAA,CAAY,oBAAoB,CAAA,CAAA;AACtD,EAAA,GAAA,CAAI,MAAM,GAAG,CAAA,CAAA;AACb,EAAA,KAAA,CAAM,KAAO,EAAA,MAAA,EAAQ,CAAG,EAAA,GAAA,EAAK,MAAM,YAAY,CAAA,CAAA;AAC/C,EAAA,GAAA,CAAI,IAAI,KAAK,CAAA,CAAA;AAEb,EAAS,SAAA,aAAA,CAAc,IAAY,EAAkB,EAAA;AACnD,IAAO,MAAA,CAAA,EAAE,CAAK,IAAA,MAAA,CAAO,EAAE,CAAA,CAAA;AACvB,IAAM,KAAA,CAAA,EAAE,IAAI,IAAK,CAAA,GAAA,CAAI,MAAM,EAAE,CAAA,EAAG,KAAM,CAAA,EAAE,CAAC,CAAA,CAAA;AACzC,IAAK,IAAA,CAAA,EAAE,IAAI,IAAK,CAAA,GAAA,CAAI,KAAK,EAAE,CAAA,EAAG,IAAK,CAAA,EAAE,CAAC,CAAA,CAAA;AACtC,IAAK,IAAA,CAAA,EAAE,CAAK,IAAA,IAAA,CAAK,EAAE,CAAA,CAAA;AAAA,GACrB;AAEA,EAAA,SAAS,YACP,CAAA,MAAA,EACA,IACA,EAAA,OAAA,EACA,EACM,EAAA;AACN,IAAM,MAAA,GAAA,GAAM,KAAK,KAAM,CAAA,IAAA,CAAK,EAAE,CAAI,GAAA,MAAA,CAAO,EAAE,CAAC,CAAA,CAAA;AAC5C,IAAA,MAAA,CAAO,MAAM,IAAK,CAAA,QAAA,CAAS,MAAQ,EAAA,CAAA,EAAG,OAAO,CAAC,CAAA,CAAA;AAC9C,IAAA,MAAA,CAAO,MAAM,GAAG,CAAA,CAAA;AAChB,IAAA,MAAA,CAAO,OAAO,IAAK,CAAA,EAAE,IAAI,EAAI,EAAA,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAA;AACvC,IAAA,MAAA,CAAO,MAAM,GAAG,CAAA,CAAA;AAChB,IAAA,MAAA,CAAO,KAAO,CAAA,CAAA,GAAA,GAAM,EAAI,EAAA,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAA;AAClC,IAAA,MAAA,CAAO,MAAM,GAAG,CAAA,CAAA;AAChB,IAAA,MAAA,CAAO,OAAO,KAAM,CAAA,EAAE,IAAI,EAAI,EAAA,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAA;AAAA,GAC1C;AACF;;ACxHA,eAAsB,GAAI,CAAA;AAAA,EACxB,GAAA;AAAA,EACA,QAAA;AAAA,EACA,EAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,MAAA;AAAA,EACA,KAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AACF,CAA2C,EAAA;AAEzC,EAAA,IAAI,SAAS,GAAK,EAAA;AAChB,IAAA,OAAO,EAAE,EAAI,EAAA,IAAA,EAAM,UAAW,CAAA,EAAA,EAAI,CAAC,CAAE,EAAA,CAAA;AAAA,GACvC;AAGA,EAAI,IAAA,IAAA,GAAO,WAAW,EAAE,CAAA,CAAA;AACxB,EAAI,IAAA,QAAA,GAAW,KAAK,YAAe,GAAA,CAAA,CAAA;AACnC,EAAM,MAAA,MAAA,GAAS,MAAO,CAAA,WAAA,CAAY,aAAa,CAAA,CAAA;AAG/C,EAAM,MAAA,MAAA,GAAS,iBAAiB,QAAU,EAAA;AAAA,IACxC,KAAA;AAAA,IACA,KAAK,GAAM,GAAA,CAAA;AAAA,IACX,aAAA,EAAe,gBAAiB,CAAA,GAAA,GAAM,KAAK,CAAA;AAAA,GAC5C,CAAA,CAAA;AAGD,EAAA,IAAI,IAAO,GAAA,CAAA,CAAA;AACX,EAAA,IAAI,KAAQ,GAAA,CAAA,CAAA;AACZ,EAAI,IAAA,IAAA,CAAA;AACJ,EAAA,WAAA,MAAiB,SAAS,MAAQ,EAAA;AAEhC,IAAA,MAAM,IAAI,KAAM,CAAA,MAAA,CAAA;AAChB,IAAA,KAAA,IAAS,CAAI,GAAA,CAAA,EAAG,CAAI,GAAA,CAAA,EAAG,EAAE,CAAG,EAAA;AAC1B,MAAI,IAAA,KAAA,CAAM,CAAC,CAAA,KAAM,cAAgB,EAAA;AAE/B,QAAQ,KAAA,GAAA,IAAA,CAAA;AAAA,OACC,MAAA,IAAA,KAAA,CAAM,CAAC,CAAA,KAAM,YAAc,EAAA;AAEpC,QAAO,MAAA,CAAA,IAAA,EAAM,CAAI,GAAA,KAAA,CAAM,CAAC,CAAA,CAAA;AAAA,OACnB,MAAA;AAEL,QAAA,MAAM,KAAQ,GAAA,WAAA,CAAY,MAAQ,EAAA,KAAA,EAAO,IAAI,CAAA,CAAA;AAC7C,QAAO,IAAA,GAAA,CAAA,CAAA;AAEP,QAAA,CAAC,MAAM,IAAI,CAAA,GAAI,IAAI,IAAM,EAAA,MAAA,EAAQ,GAAG,KAAK,CAAA,CAAA;AAEzC,QAAA,IAAI,IAAK,CAAA,IAAA,GAAO,uBAAuB,CAAA,KAAM,SAAW,EAAA;AAEtD,UAAA,aAAA,CAAc,IAAK,CAAA,IAAA,GAAO,uBAAuB,CAAA,EAAG,KAAK,CAAA,CAAA;AAAA,SACpD,MAAA;AAEL,UAAK,IAAA,CAAA,IAAA,GAAO,uBAAuB,CAAI,GAAA,QAAA,CAAA;AACvC,UAAA,UAAA,CAAW,YAAY,KAAK,CAAA,CAAA;AAAA,SAC9B;AAAA,OACF;AAAA,KACF;AAAA,GACF;AAEA,EAAS,SAAA,UAAA,CAAW,OAAe,IAAoB,EAAA;AACrD,IAAA,MAAA,CAAO,KAAK,CAAI,GAAA,CAAA,CAAA;AAChB,IAAA,KAAA,CAAM,KAAK,CAAI,GAAA,IAAA,CAAA;AACf,IAAA,IAAA,CAAK,KAAK,CAAI,GAAA,IAAA,CAAA;AACd,IAAA,IAAA,CAAK,KAAK,CAAI,GAAA,IAAA,CAAA;AAAA,GAChB;AAEA,EAAS,SAAA,aAAA,CAAc,OAAe,IAAoB,EAAA;AACxD,IAAA,EAAE,OAAO,KAAK,CAAA,CAAA;AACd,IAAM,KAAA,CAAA,KAAK,IAAI,KAAM,CAAA,KAAK,KAAK,IAAO,GAAA,KAAA,CAAM,KAAK,CAAI,GAAA,IAAA,CAAA;AACrD,IAAK,IAAA,CAAA,KAAK,IAAI,IAAK,CAAA,KAAK,KAAK,IAAO,GAAA,IAAA,CAAK,KAAK,CAAI,GAAA,IAAA,CAAA;AAClD,IAAA,IAAA,CAAK,KAAK,CAAK,IAAA,IAAA,CAAA;AAAA,GACjB;AAEA,EAAO,OAAA,EAAE,IAAI,IAAK,EAAA,CAAA;AACpB,CAAA;AAEgB,SAAA,WAAA,CAAY,CAAW,EAAA,GAAA,EAAa,GAAqB,EAAA;AACvE,EAAI,IAAA,CAAA,CAAE,GAAG,CAAA,KAAM,UAAY,EAAA;AACzB,IAAO,OAAA,EAAE,GAAM,GAAA,CAAA,GAAI,GACf,GAAA,EAAE,EAAK,GAAA,CAAA,CAAE,GAAG,CAAA,GAAI,CAAE,CAAA,GAAA,GAAM,CAAC,CAAA,GAAI,YAC7B,CAAA,GAAA,EAAE,GAAM,GAAA,CAAA,CAAE,GAAG,CAAA,GAAI,EAAK,GAAA,CAAA,CAAE,GAAM,GAAA,CAAC,CAAI,GAAA,CAAA,CAAE,GAAM,GAAA,CAAC,CAAI,GAAA,aAAA,CAAA,CAAA;AAAA,GACtD;AACA,EAAO,OAAA,GAAA,GAAM,CAAI,GAAA,GAAA,GACb,EAAK,GAAA,CAAA,CAAE,GAAG,CAAI,GAAA,CAAA,CAAE,GAAM,GAAA,CAAC,CAAI,GAAA,YAAA,GAC3B,MAAM,CAAE,CAAA,GAAG,CAAI,GAAA,EAAA,GAAK,CAAE,CAAA,GAAA,GAAM,CAAC,CAAI,GAAA,CAAA,CAAE,GAAM,GAAA,CAAC,CAAI,GAAA,aAAA,CAAA;AACpD;;AC5FA,IAAI,YAAc,EAAA;AAChB,EAAM,MAAA,UAAA,GAAa,aAAc,CAAA,MAAA,CAAA,IAAA,CAAY,GAAG,CAAA,CAAA;AAChD,EAAAC,KAAA,CAAQ,QAAQ,IAAK,CAAA,CAAC,CAAG,EAAA,UAAA,EAAY,sBAAsB,CAAA,CAAA;AAC7D,CAAO,MAAA;AACL,EAAY,UAAA,CAAA,WAAA,CAAY,SAAW,EAAA,OAAO,GAAuB,KAAA;AAC/D,IAAM,MAAA,GAAA,GAAM,MAAMC,GAAA,CAAU,GAAG,CAAA,CAAA;AAC/B,IAAA,UAAA,CAAY,YAAY,GAAK,EAAA,CAAC,GAAI,CAAA,IAAA,CAAK,MAAM,CAAC,CAAA,CAAA;AAAA,GAC/C,CAAA,CAAA;AACH"} \ No newline at end of file +{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN, UTF8_BN_LEN } from \"./utf8\";\n\n// Trie static properties\n\n/**\n * Represents null / undefined.\n */\nexport const TRIE_NULL = 0;\n\n/**\n * The minimum size a trie.\n */\nexport const MIN_TRIE_SIZE = 524288; // 2 MiB\n\n/**\n * The default growth factor for growing the size of a trie.\n */\nexport const TRIE_GROWTH_FACTOR = 1.618; // ~phi\n\n/**\n * All trie properties are represented by 32 bits (4 bytes).\n */\nexport const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT;\n\nexport const TRIE_BODY_NODE_CHILDREN_LEN = UTF8_BN_LEN;\nexport const TRIE_TAIL_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\n\n// Trie child pointer properties\n\nexport const TRIE_CHILD_IDX_IDX = 0;\nexport const TRIE_CHILD_IDX_UTS = 1;\n\nexport const TRIE_CHILD_UTS = TRIE_CHILD_IDX_UTS;\n\n// Trie redirect pointer properties\n\nexport const TRIE_RED_ID_IDX = 0;\nexport const TRIE_RED_ID_UTS = 1;\n\nexport const TRIE_RED_VALUE_IDX_IDX = 1;\nexport const TRIE_RED_VALUE_IDX_UTS = 1;\n\nexport const TRIE_RED_UTS = TRIE_RED_ID_UTS + TRIE_RED_VALUE_IDX_UTS;\n\n// Trie node properties\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_UTS = 1;\n\nexport const TRIE_NODE_VALUE_IDX_IDX = 1;\nexport const TRIE_NODE_VALUE_IDX_UTS = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_BODY_NODE_CHILDREN_UTS =\n TRIE_CHILD_UTS * TRIE_BODY_NODE_CHILDREN_LEN;\nexport const TRIE_TAIL_NODE_CHILDREN_UTS =\n TRIE_CHILD_UTS * TRIE_TAIL_NODE_CHILDREN_LEN;\n\nexport const TRIE_BODY_NODE_UTS =\n TRIE_NODE_ID_UTS + TRIE_NODE_VALUE_IDX_UTS + TRIE_BODY_NODE_CHILDREN_UTS;\n\nexport const TRIE_TAIL_NODE_UTS =\n TRIE_NODE_ID_UTS + TRIE_NODE_VALUE_IDX_UTS + TRIE_TAIL_NODE_CHILDREN_UTS;\n\n// Trie properties\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_UTS = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_UTS = TRIE_TAIL_NODE_UTS;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_HEADER_UTS = TRIE_SIZE_UTS + TRIE_ROOT_UTS;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n MIN_TRIE_SIZE,\n TRIE_CHILD_UTS,\n TRIE_CHILD_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_HEADER_UTS,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_RED_UTS,\n TRIE_RED_VALUE_IDX_IDX,\n TRIE_RED_ID_IDX,\n TRIE_TAIL_NODE_CHILDREN_LEN,\n TRIE_TAIL_NODE_CHILDREN_UTS,\n TRIE_TAIL_NODE_UTS,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_UTS * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_CHILD_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_TAIL_NODE_UTS > trie.length) {\n trie = grow(trie, child + TRIE_TAIL_NODE_UTS);\n }\n trie[TRIE_SIZE_IDX] += TRIE_TAIL_NODE_UTS;\n // Attach and initialize node\n trie[index + TRIE_CHILD_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array {\n const minSize = TRIE_HEADER_UTS;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n console.log(\"D\");\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_TAIL_NODE_CHILDREN_UTS;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_CHILD_UTS;\n bi += TRIE_CHILD_UTS;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_CHILD_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_RED_UTS > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_RED_UTS);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_RED_UTS;\n // Add new redirect\n tries[at][li + TRIE_RED_ID_IDX] = rt;\n tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_CHILD_UTS;\n bi += TRIE_CHILD_UTS;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, 0, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childKey, childPtr] = stack[top];\n\n // Check if end of children array\n if (childKey >= TRIE_TAIL_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n ++stack[top][1];\n stack[top][2] += TRIE_CHILD_UTS;\n\n // If just reached node\n if (childKey === 0) {\n // Check if the node has a value\n const nodeIndex = childPtr - TRIE_NODE_CHILDREN_IDX;\n const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print the node's value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n }\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX];\n if (childI !== TRIE_NULL) {\n // Resolve child if redirect\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX];\n trieI = childTrieI;\n }\n // Add the child to the stack\n key[top] = childKey + UTF8_B0_MIN;\n stack[++top] = [trieI, 0, childI + TRIE_NODE_CHILDREN_IDX];\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/utf8Trie\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const numVals = MAX_STATIONS * maxWorkers + 1;\n let bpe = Uint32Array.BYTES_PER_ELEMENT;\n const counts = new Uint32Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Int16Array.BYTES_PER_ELEMENT;\n const maxes = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n const mins = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Float64Array.BYTES_PER_ELEMENT;\n const sums = new Float64Array(new SharedArrayBuffer(bpe * numVals));\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n counts,\n end,\n filePath,\n id,\n maxes,\n mins,\n start,\n sums,\n } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n tries[res.id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 1; i < maxWorkers; ++i) {\n mergeLeft(tries, 0, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(ai: number, bi: number): void {\n counts[ai] += counts[bi];\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n mins[ai] = Math.min(mins[ai], mins[bi]);\n sums[ai] += sums[bi];\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi] / counts[vi]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: WorkerRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n counts[index] = 1;\n maxes[index] = temp;\n mins[index] = temp;\n sums[index] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n ++counts[index];\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n sums[index] += temp;\n }\n\n return { id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n return ++min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [res.trie.buffer]);\n });\n}\n"],"names":["at","bt","run","runMain","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts b/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts index 047d3d5..b9d0659 100644 --- a/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts +++ b/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts @@ -1,7 +1,7 @@ -// Trie static properties - import { UTF8_B0_2B_LEN, UTF8_BN_LEN } from "./utf8"; +// Trie static properties + /** * Represents null / undefined. */ @@ -22,53 +22,53 @@ export const TRIE_GROWTH_FACTOR = 1.618; // ~phi */ export const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT; -export const TRIE_BODY_NODE_CHILDREN_NUM = UTF8_BN_LEN; -export const TRIE_TAIL_NODE_CHILDREN_NUM = UTF8_B0_2B_LEN; +export const TRIE_BODY_NODE_CHILDREN_LEN = UTF8_BN_LEN; +export const TRIE_TAIL_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN; // Trie child pointer properties export const TRIE_CHILD_IDX_IDX = 0; -export const TRIE_CHILD_IDX_LEN = 1; +export const TRIE_CHILD_IDX_UTS = 1; -export const TRIE_CHILD_LEN = TRIE_CHILD_IDX_LEN; +export const TRIE_CHILD_UTS = TRIE_CHILD_IDX_UTS; // Trie redirect pointer properties export const TRIE_RED_ID_IDX = 0; -export const TRIE_RED_ID_LEN = 1; +export const TRIE_RED_ID_UTS = 1; export const TRIE_RED_VALUE_IDX_IDX = 1; -export const TRIE_RED_VALUE_IDX_LEN = 1; +export const TRIE_RED_VALUE_IDX_UTS = 1; -export const TRIE_RED_LEN = TRIE_RED_ID_LEN + TRIE_RED_VALUE_IDX_LEN; +export const TRIE_RED_UTS = TRIE_RED_ID_UTS + TRIE_RED_VALUE_IDX_UTS; // Trie node properties export const TRIE_NODE_ID_IDX = 0; -export const TRIE_NODE_ID_LEN = 1; +export const TRIE_NODE_ID_UTS = 1; export const TRIE_NODE_VALUE_IDX_IDX = 1; -export const TRIE_NODE_VALUE_IDX_LEN = 1; +export const TRIE_NODE_VALUE_IDX_UTS = 1; export const TRIE_NODE_CHILDREN_IDX = 2; -export const TRIE_BODY_NODE_CHILDREN_LEN = - TRIE_CHILD_LEN * TRIE_BODY_NODE_CHILDREN_NUM; -export const TRIE_TAIL_NODE_CHILDREN_LEN = - TRIE_CHILD_LEN * TRIE_TAIL_NODE_CHILDREN_NUM; +export const TRIE_BODY_NODE_CHILDREN_UTS = + TRIE_CHILD_UTS * TRIE_BODY_NODE_CHILDREN_LEN; +export const TRIE_TAIL_NODE_CHILDREN_UTS = + TRIE_CHILD_UTS * TRIE_TAIL_NODE_CHILDREN_LEN; -export const TRIE_BODY_NODE_LEN = - TRIE_NODE_ID_LEN + TRIE_NODE_VALUE_IDX_LEN + TRIE_BODY_NODE_CHILDREN_LEN; +export const TRIE_BODY_NODE_UTS = + TRIE_NODE_ID_UTS + TRIE_NODE_VALUE_IDX_UTS + TRIE_BODY_NODE_CHILDREN_UTS; -export const TRIE_TAIL_NODE_LEN = - TRIE_NODE_ID_LEN + TRIE_NODE_VALUE_IDX_LEN + TRIE_TAIL_NODE_CHILDREN_LEN; +export const TRIE_TAIL_NODE_UTS = + TRIE_NODE_ID_UTS + TRIE_NODE_VALUE_IDX_UTS + TRIE_TAIL_NODE_CHILDREN_UTS; // Trie properties export const TRIE_SIZE_IDX = 0; -export const TRIE_SIZE_LEN = 1; +export const TRIE_SIZE_UTS = 1; export const TRIE_ROOT_IDX = 1; -export const TRIE_ROOT_LEN = TRIE_TAIL_NODE_LEN; +export const TRIE_ROOT_UTS = TRIE_TAIL_NODE_UTS; -export const TRIE_HEADER_LEN = TRIE_SIZE_LEN + TRIE_ROOT_LEN; export const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX; +export const TRIE_HEADER_UTS = TRIE_SIZE_UTS + TRIE_ROOT_UTS; diff --git a/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts b/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts index fa83118..a3f5230 100644 --- a/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts +++ b/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts @@ -2,10 +2,10 @@ import { WriteStream } from "node:fs"; import { MIN_TRIE_SIZE, - TRIE_CHILD_LEN, + TRIE_CHILD_UTS, TRIE_CHILD_IDX_IDX, TRIE_GROWTH_FACTOR, - TRIE_HEADER_LEN, + TRIE_HEADER_UTS, TRIE_ID_IDX, TRIE_NODE_CHILDREN_IDX, TRIE_NODE_ID_IDX, @@ -13,12 +13,12 @@ import { TRIE_NULL, TRIE_ROOT_IDX, TRIE_SIZE_IDX, - TRIE_RED_LEN, + TRIE_RED_UTS, TRIE_RED_VALUE_IDX_IDX, TRIE_RED_ID_IDX, - TRIE_TAIL_NODE_CHILDREN_NUM, TRIE_TAIL_NODE_CHILDREN_LEN, - TRIE_TAIL_NODE_LEN, + TRIE_TAIL_NODE_CHILDREN_UTS, + TRIE_TAIL_NODE_UTS, } from "../constants/utf8Trie"; import { UTF8_B0_MIN } from "../constants/utf8"; @@ -31,15 +31,15 @@ export function add( let index = TRIE_ROOT_IDX; while (min < max) { index += - TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_LEN * (key[min++] - UTF8_B0_MIN); + TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_UTS * (key[min++] - UTF8_B0_MIN); let child = trie[index + TRIE_CHILD_IDX_IDX]; if (child === TRIE_NULL) { // Allocate new node child = trie[TRIE_SIZE_IDX]; - if (child + TRIE_TAIL_NODE_LEN > trie.length) { - trie = grow(trie, child + TRIE_TAIL_NODE_LEN); + if (child + TRIE_TAIL_NODE_UTS > trie.length) { + trie = grow(trie, child + TRIE_TAIL_NODE_UTS); } - trie[TRIE_SIZE_IDX] += TRIE_TAIL_NODE_LEN; + trie[TRIE_SIZE_IDX] += TRIE_TAIL_NODE_UTS; // Attach and initialize node trie[index + TRIE_CHILD_IDX_IDX] = child; trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX]; @@ -51,7 +51,7 @@ export function add( } export function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array { - const minSize = TRIE_HEADER_LEN; + const minSize = TRIE_HEADER_UTS; const trie = new Int32Array(Math.max(minSize, size)); trie[TRIE_SIZE_IDX] = minSize; trie[TRIE_ID_IDX] = id; @@ -101,14 +101,14 @@ export function mergeLeft( bi += TRIE_NODE_CHILDREN_IDX; // Traverse right children - const bn = bi + TRIE_TAIL_NODE_CHILDREN_LEN; + const bn = bi + TRIE_TAIL_NODE_CHILDREN_UTS; while (bi < bn) { // If right child is null let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX]; if (ri === TRIE_NULL) { // Move to next children - ai += TRIE_CHILD_LEN; - bi += TRIE_CHILD_LEN; + ai += TRIE_CHILD_UTS; + bi += TRIE_CHILD_UTS; continue; } @@ -123,10 +123,10 @@ export function mergeLeft( if (li === TRIE_NULL) { // Allocate new redirect in left trie li = tries[at][TRIE_SIZE_IDX]; - if (li + TRIE_RED_LEN > tries[at].length) { - tries[at] = grow(tries[at], li + TRIE_RED_LEN); + if (li + TRIE_RED_UTS > tries[at].length) { + tries[at] = grow(tries[at], li + TRIE_RED_UTS); } - tries[at][TRIE_SIZE_IDX] += TRIE_RED_LEN; + tries[at][TRIE_SIZE_IDX] += TRIE_RED_UTS; // Add new redirect tries[at][li + TRIE_RED_ID_IDX] = rt; tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri; @@ -141,8 +141,8 @@ export function mergeLeft( } // Move to next children - ai += TRIE_CHILD_LEN; - bi += TRIE_CHILD_LEN; + ai += TRIE_CHILD_UTS; + bi += TRIE_CHILD_UTS; } } queue.splice(0, Q); @@ -171,14 +171,14 @@ export function print( let [trieI, childKey, childPtr] = stack[top]; // Check if end of children array - if (childKey >= TRIE_TAIL_NODE_CHILDREN_NUM) { + if (childKey >= TRIE_TAIL_NODE_CHILDREN_LEN) { --top; continue; } // Update stack top ++stack[top][1]; - stack[top][2] += TRIE_CHILD_LEN; + stack[top][2] += TRIE_CHILD_UTS; // If just reached node if (childKey === 0) { From eb5ba802d90f7ea8541c146a9a9a87d29008dd57 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Wed, 22 May 2024 17:09:17 -0400 Subject: [PATCH 08/69] Rename utf8Trie constants again --- .../havelessbemore/src/constants/utf8Trie.ts | 36 +++++++++--------- .../havelessbemore/src/utils/utf8Trie.ts | 38 +++++++++---------- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts b/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts index b9d0659..2882157 100644 --- a/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts +++ b/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts @@ -28,47 +28,47 @@ export const TRIE_TAIL_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN; // Trie child pointer properties export const TRIE_CHILD_IDX_IDX = 0; -export const TRIE_CHILD_IDX_UTS = 1; +export const TRIE_CHILD_IDX_MEM = 1; -export const TRIE_CHILD_UTS = TRIE_CHILD_IDX_UTS; +export const TRIE_CHILD_MEM = TRIE_CHILD_IDX_MEM; // Trie redirect pointer properties export const TRIE_RED_ID_IDX = 0; -export const TRIE_RED_ID_UTS = 1; +export const TRIE_RED_ID_MEM = 1; export const TRIE_RED_VALUE_IDX_IDX = 1; -export const TRIE_RED_VALUE_IDX_UTS = 1; +export const TRIE_RED_VALUE_IDX_MEM = 1; -export const TRIE_RED_UTS = TRIE_RED_ID_UTS + TRIE_RED_VALUE_IDX_UTS; +export const TRIE_RED_MEM = TRIE_RED_ID_MEM + TRIE_RED_VALUE_IDX_MEM; // Trie node properties export const TRIE_NODE_ID_IDX = 0; -export const TRIE_NODE_ID_UTS = 1; +export const TRIE_NODE_ID_MEM = 1; export const TRIE_NODE_VALUE_IDX_IDX = 1; -export const TRIE_NODE_VALUE_IDX_UTS = 1; +export const TRIE_NODE_VALUE_IDX_MEM = 1; export const TRIE_NODE_CHILDREN_IDX = 2; -export const TRIE_BODY_NODE_CHILDREN_UTS = - TRIE_CHILD_UTS * TRIE_BODY_NODE_CHILDREN_LEN; -export const TRIE_TAIL_NODE_CHILDREN_UTS = - TRIE_CHILD_UTS * TRIE_TAIL_NODE_CHILDREN_LEN; +export const TRIE_BODY_NODE_CHILDREN_MEM = + TRIE_CHILD_MEM * TRIE_BODY_NODE_CHILDREN_LEN; +export const TRIE_TAIL_NODE_CHILDREN_MEM = + TRIE_CHILD_MEM * TRIE_TAIL_NODE_CHILDREN_LEN; -export const TRIE_BODY_NODE_UTS = - TRIE_NODE_ID_UTS + TRIE_NODE_VALUE_IDX_UTS + TRIE_BODY_NODE_CHILDREN_UTS; +export const TRIE_BODY_NODE_MEM = + TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_IDX_MEM + TRIE_BODY_NODE_CHILDREN_MEM; -export const TRIE_TAIL_NODE_UTS = - TRIE_NODE_ID_UTS + TRIE_NODE_VALUE_IDX_UTS + TRIE_TAIL_NODE_CHILDREN_UTS; +export const TRIE_TAIL_NODE_MEM = + TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_IDX_MEM + TRIE_TAIL_NODE_CHILDREN_MEM; // Trie properties export const TRIE_SIZE_IDX = 0; -export const TRIE_SIZE_UTS = 1; +export const TRIE_SIZE_MEM = 1; export const TRIE_ROOT_IDX = 1; -export const TRIE_ROOT_UTS = TRIE_TAIL_NODE_UTS; +export const TRIE_ROOT_MEM = TRIE_TAIL_NODE_MEM; export const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX; -export const TRIE_HEADER_UTS = TRIE_SIZE_UTS + TRIE_ROOT_UTS; +export const TRIE_HEADER_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM; diff --git a/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts b/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts index a3f5230..b65c59d 100644 --- a/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts +++ b/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts @@ -2,10 +2,10 @@ import { WriteStream } from "node:fs"; import { MIN_TRIE_SIZE, - TRIE_CHILD_UTS, + TRIE_CHILD_MEM, TRIE_CHILD_IDX_IDX, TRIE_GROWTH_FACTOR, - TRIE_HEADER_UTS, + TRIE_HEADER_MEM, TRIE_ID_IDX, TRIE_NODE_CHILDREN_IDX, TRIE_NODE_ID_IDX, @@ -13,12 +13,12 @@ import { TRIE_NULL, TRIE_ROOT_IDX, TRIE_SIZE_IDX, - TRIE_RED_UTS, + TRIE_RED_MEM, TRIE_RED_VALUE_IDX_IDX, TRIE_RED_ID_IDX, TRIE_TAIL_NODE_CHILDREN_LEN, - TRIE_TAIL_NODE_CHILDREN_UTS, - TRIE_TAIL_NODE_UTS, + TRIE_TAIL_NODE_CHILDREN_MEM, + TRIE_TAIL_NODE_MEM, } from "../constants/utf8Trie"; import { UTF8_B0_MIN } from "../constants/utf8"; @@ -31,15 +31,15 @@ export function add( let index = TRIE_ROOT_IDX; while (min < max) { index += - TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_UTS * (key[min++] - UTF8_B0_MIN); + TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_MEM * (key[min++] - UTF8_B0_MIN); let child = trie[index + TRIE_CHILD_IDX_IDX]; if (child === TRIE_NULL) { // Allocate new node child = trie[TRIE_SIZE_IDX]; - if (child + TRIE_TAIL_NODE_UTS > trie.length) { - trie = grow(trie, child + TRIE_TAIL_NODE_UTS); + if (child + TRIE_TAIL_NODE_MEM > trie.length) { + trie = grow(trie, child + TRIE_TAIL_NODE_MEM); } - trie[TRIE_SIZE_IDX] += TRIE_TAIL_NODE_UTS; + trie[TRIE_SIZE_IDX] += TRIE_TAIL_NODE_MEM; // Attach and initialize node trie[index + TRIE_CHILD_IDX_IDX] = child; trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX]; @@ -51,7 +51,7 @@ export function add( } export function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array { - const minSize = TRIE_HEADER_UTS; + const minSize = TRIE_HEADER_MEM; const trie = new Int32Array(Math.max(minSize, size)); trie[TRIE_SIZE_IDX] = minSize; trie[TRIE_ID_IDX] = id; @@ -101,14 +101,14 @@ export function mergeLeft( bi += TRIE_NODE_CHILDREN_IDX; // Traverse right children - const bn = bi + TRIE_TAIL_NODE_CHILDREN_UTS; + const bn = bi + TRIE_TAIL_NODE_CHILDREN_MEM; while (bi < bn) { // If right child is null let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX]; if (ri === TRIE_NULL) { // Move to next children - ai += TRIE_CHILD_UTS; - bi += TRIE_CHILD_UTS; + ai += TRIE_CHILD_MEM; + bi += TRIE_CHILD_MEM; continue; } @@ -123,10 +123,10 @@ export function mergeLeft( if (li === TRIE_NULL) { // Allocate new redirect in left trie li = tries[at][TRIE_SIZE_IDX]; - if (li + TRIE_RED_UTS > tries[at].length) { - tries[at] = grow(tries[at], li + TRIE_RED_UTS); + if (li + TRIE_RED_MEM > tries[at].length) { + tries[at] = grow(tries[at], li + TRIE_RED_MEM); } - tries[at][TRIE_SIZE_IDX] += TRIE_RED_UTS; + tries[at][TRIE_SIZE_IDX] += TRIE_RED_MEM; // Add new redirect tries[at][li + TRIE_RED_ID_IDX] = rt; tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri; @@ -141,8 +141,8 @@ export function mergeLeft( } // Move to next children - ai += TRIE_CHILD_UTS; - bi += TRIE_CHILD_UTS; + ai += TRIE_CHILD_MEM; + bi += TRIE_CHILD_MEM; } } queue.splice(0, Q); @@ -178,7 +178,7 @@ export function print( // Update stack top ++stack[top][1]; - stack[top][2] += TRIE_CHILD_UTS; + stack[top][2] += TRIE_CHILD_MEM; // If just reached node if (childKey === 0) { From 5a880aa6b142a610d404fc33bb82e333c3b34afe Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Wed, 22 May 2024 18:33:31 -0400 Subject: [PATCH 09/69] Refactor print() function for utf8trie. Stop update for variable number of children depending on UTF8 byte value due to negligible impact --- src/main/nodejs/havelessbemore/dist/index.cjs | 97 +++++++++---------- .../nodejs/havelessbemore/dist/index.cjs.map | 2 +- src/main/nodejs/havelessbemore/dist/index.mjs | 97 +++++++++---------- .../nodejs/havelessbemore/dist/index.mjs.map | 2 +- .../havelessbemore/src/constants/utf8Trie.ts | 20 ++-- .../havelessbemore/src/utils/utf8Trie.ts | 72 +++++++------- 6 files changed, 137 insertions(+), 153 deletions(-) diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs b/src/main/nodejs/havelessbemore/dist/index.cjs index abebab9..cc7eb4d 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs +++ b/src/main/nodejs/havelessbemore/dist/index.cjs @@ -68,40 +68,40 @@ function getHighWaterMark(size) { const TRIE_NULL = 0; const MIN_TRIE_SIZE = 524288; const TRIE_GROWTH_FACTOR = 1.618; -const TRIE_TAIL_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN; const TRIE_CHILD_IDX_IDX = 0; -const TRIE_CHILD_IDX_UTS = 1; -const TRIE_CHILD_UTS = TRIE_CHILD_IDX_UTS; +const TRIE_CHILD_IDX_MEM = 1; +const TRIE_CHILD_MEM = TRIE_CHILD_IDX_MEM; const TRIE_RED_ID_IDX = 0; -const TRIE_RED_ID_UTS = 1; +const TRIE_RED_ID_MEM = 1; const TRIE_RED_VALUE_IDX_IDX = 1; -const TRIE_RED_VALUE_IDX_UTS = 1; -const TRIE_RED_UTS = TRIE_RED_ID_UTS + TRIE_RED_VALUE_IDX_UTS; +const TRIE_RED_VALUE_IDX_MEM = 1; +const TRIE_RED_MEM = TRIE_RED_ID_MEM + TRIE_RED_VALUE_IDX_MEM; const TRIE_NODE_ID_IDX = 0; -const TRIE_NODE_ID_UTS = 1; +const TRIE_NODE_ID_MEM = 1; const TRIE_NODE_VALUE_IDX_IDX = 1; -const TRIE_NODE_VALUE_IDX_UTS = 1; +const TRIE_NODE_VALUE_IDX_MEM = 1; const TRIE_NODE_CHILDREN_IDX = 2; -const TRIE_TAIL_NODE_CHILDREN_UTS = TRIE_CHILD_UTS * TRIE_TAIL_NODE_CHILDREN_LEN; -const TRIE_TAIL_NODE_UTS = TRIE_NODE_ID_UTS + TRIE_NODE_VALUE_IDX_UTS + TRIE_TAIL_NODE_CHILDREN_UTS; +const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN; +const TRIE_NODE_CHILDREN_MEM = TRIE_CHILD_MEM * TRIE_NODE_CHILDREN_LEN; +const TRIE_NODE_MEM = TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_IDX_MEM + TRIE_NODE_CHILDREN_MEM; const TRIE_SIZE_IDX = 0; -const TRIE_SIZE_UTS = 1; +const TRIE_SIZE_MEM = 1; const TRIE_ROOT_IDX = 1; -const TRIE_ROOT_UTS = TRIE_TAIL_NODE_UTS; +const TRIE_ROOT_MEM = TRIE_NODE_MEM; const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX; -const TRIE_HEADER_UTS = TRIE_SIZE_UTS + TRIE_ROOT_UTS; +const TRIE_HEADER_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM; function add(trie, key, min, max) { let index = TRIE_ROOT_IDX; while (min < max) { - index += TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_UTS * (key[min++] - UTF8_B0_MIN); + index += TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_MEM * (key[min++] - UTF8_B0_MIN); let child = trie[index + TRIE_CHILD_IDX_IDX]; if (child === TRIE_NULL) { child = trie[TRIE_SIZE_IDX]; - if (child + TRIE_TAIL_NODE_UTS > trie.length) { - trie = grow(trie, child + TRIE_TAIL_NODE_UTS); + if (child + TRIE_NODE_MEM > trie.length) { + trie = grow(trie, child + TRIE_NODE_MEM); } - trie[TRIE_SIZE_IDX] += TRIE_TAIL_NODE_UTS; + trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM; trie[index + TRIE_CHILD_IDX_IDX] = child; trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX]; } @@ -110,14 +110,13 @@ function add(trie, key, min, max) { return [trie, index]; } function createTrie(id = 0, size = MIN_TRIE_SIZE) { - const minSize = TRIE_HEADER_UTS; + const minSize = TRIE_HEADER_MEM; const trie = new Int32Array(Math.max(minSize, size)); trie[TRIE_SIZE_IDX] = minSize; trie[TRIE_ID_IDX] = id; return trie; } function grow(trie, minSize = 0) { - console.log("D"); const length = trie[TRIE_SIZE_IDX]; minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR)); const next = new Int32Array(minSize); @@ -145,12 +144,12 @@ function mergeLeft(tries, at, bt, mergeFn) { } ai += TRIE_NODE_CHILDREN_IDX; bi += TRIE_NODE_CHILDREN_IDX; - const bn = bi + TRIE_TAIL_NODE_CHILDREN_UTS; + const bn = bi + TRIE_NODE_CHILDREN_MEM; while (bi < bn) { let ri = tries[bt2][bi + TRIE_CHILD_IDX_IDX]; if (ri === TRIE_NULL) { - ai += TRIE_CHILD_UTS; - bi += TRIE_CHILD_UTS; + ai += TRIE_CHILD_MEM; + bi += TRIE_CHILD_MEM; continue; } const rt = tries[bt2][ri + TRIE_NODE_ID_IDX]; @@ -160,10 +159,10 @@ function mergeLeft(tries, at, bt, mergeFn) { let li = tries[at2][ai + TRIE_CHILD_IDX_IDX]; if (li === TRIE_NULL) { li = tries[at2][TRIE_SIZE_IDX]; - if (li + TRIE_RED_UTS > tries[at2].length) { - tries[at2] = grow(tries[at2], li + TRIE_RED_UTS); + if (li + TRIE_RED_MEM > tries[at2].length) { + tries[at2] = grow(tries[at2], li + TRIE_RED_MEM); } - tries[at2][TRIE_SIZE_IDX] += TRIE_RED_UTS; + tries[at2][TRIE_SIZE_IDX] += TRIE_RED_MEM; tries[at2][li + TRIE_RED_ID_IDX] = rt; tries[at2][li + TRIE_RED_VALUE_IDX_IDX] = ri; } else { @@ -173,8 +172,8 @@ function mergeLeft(tries, at, bt, mergeFn) { } queue.push([lt, li, rt, ri]); } - ai += TRIE_CHILD_UTS; - bi += TRIE_CHILD_UTS; + ai += TRIE_CHILD_MEM; + bi += TRIE_CHILD_MEM; } } queue.splice(0, Q); @@ -182,37 +181,35 @@ function mergeLeft(tries, at, bt, mergeFn) { } function print(tries, key, trieIndex, stream, separator = "", callbackFn) { const stack = new Array(key.length + 1); - stack[0] = [trieIndex, 0, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX]; + stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0]; let top = 0; let tail = false; do { - let [trieI, childKey, childPtr] = stack[top]; - if (childKey >= TRIE_TAIL_NODE_CHILDREN_LEN) { + let [trieI, childPtr, numChild] = stack[top]; + if (numChild >= TRIE_NODE_CHILDREN_LEN) { --top; continue; } - ++stack[top][1]; - stack[top][2] += TRIE_CHILD_UTS; - if (childKey === 0) { - const nodeIndex = childPtr - TRIE_NODE_CHILDREN_IDX; - const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX]; - if (valueIndex !== TRIE_NULL) { - if (tail) { - stream.write(separator); - } - tail = true; - callbackFn(stream, key, top, valueIndex); - } - } + stack[top][1] += TRIE_CHILD_MEM; + ++stack[top][2]; let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX]; - if (childI !== TRIE_NULL) { - const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX]; - if (trieI !== childTrieI) { - childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX]; - trieI = childTrieI; + if (childI === TRIE_NULL) { + continue; + } + const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX]; + if (trieI !== childTrieI) { + childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX]; + trieI = childTrieI; + } + key[top] = numChild + UTF8_B0_MIN; + stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0]; + const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX_IDX]; + if (valueIndex !== TRIE_NULL) { + if (tail) { + stream.write(separator); } - key[top] = childKey + UTF8_B0_MIN; - stack[++top] = [trieI, 0, childI + TRIE_NODE_CHILDREN_IDX]; + tail = true; + callbackFn(stream, key, top, valueIndex); } } while (top >= 0); } diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs.map b/src/main/nodejs/havelessbemore/dist/index.cjs.map index 9e4e201..85a173e 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.cjs.map @@ -1 +1 @@ -{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN, UTF8_BN_LEN } from \"./utf8\";\n\n// Trie static properties\n\n/**\n * Represents null / undefined.\n */\nexport const TRIE_NULL = 0;\n\n/**\n * The minimum size a trie.\n */\nexport const MIN_TRIE_SIZE = 524288; // 2 MiB\n\n/**\n * The default growth factor for growing the size of a trie.\n */\nexport const TRIE_GROWTH_FACTOR = 1.618; // ~phi\n\n/**\n * All trie properties are represented by 32 bits (4 bytes).\n */\nexport const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT;\n\nexport const TRIE_BODY_NODE_CHILDREN_LEN = UTF8_BN_LEN;\nexport const TRIE_TAIL_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\n\n// Trie child pointer properties\n\nexport const TRIE_CHILD_IDX_IDX = 0;\nexport const TRIE_CHILD_IDX_UTS = 1;\n\nexport const TRIE_CHILD_UTS = TRIE_CHILD_IDX_UTS;\n\n// Trie redirect pointer properties\n\nexport const TRIE_RED_ID_IDX = 0;\nexport const TRIE_RED_ID_UTS = 1;\n\nexport const TRIE_RED_VALUE_IDX_IDX = 1;\nexport const TRIE_RED_VALUE_IDX_UTS = 1;\n\nexport const TRIE_RED_UTS = TRIE_RED_ID_UTS + TRIE_RED_VALUE_IDX_UTS;\n\n// Trie node properties\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_UTS = 1;\n\nexport const TRIE_NODE_VALUE_IDX_IDX = 1;\nexport const TRIE_NODE_VALUE_IDX_UTS = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_BODY_NODE_CHILDREN_UTS =\n TRIE_CHILD_UTS * TRIE_BODY_NODE_CHILDREN_LEN;\nexport const TRIE_TAIL_NODE_CHILDREN_UTS =\n TRIE_CHILD_UTS * TRIE_TAIL_NODE_CHILDREN_LEN;\n\nexport const TRIE_BODY_NODE_UTS =\n TRIE_NODE_ID_UTS + TRIE_NODE_VALUE_IDX_UTS + TRIE_BODY_NODE_CHILDREN_UTS;\n\nexport const TRIE_TAIL_NODE_UTS =\n TRIE_NODE_ID_UTS + TRIE_NODE_VALUE_IDX_UTS + TRIE_TAIL_NODE_CHILDREN_UTS;\n\n// Trie properties\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_UTS = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_UTS = TRIE_TAIL_NODE_UTS;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_HEADER_UTS = TRIE_SIZE_UTS + TRIE_ROOT_UTS;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n MIN_TRIE_SIZE,\n TRIE_CHILD_UTS,\n TRIE_CHILD_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_HEADER_UTS,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_RED_UTS,\n TRIE_RED_VALUE_IDX_IDX,\n TRIE_RED_ID_IDX,\n TRIE_TAIL_NODE_CHILDREN_LEN,\n TRIE_TAIL_NODE_CHILDREN_UTS,\n TRIE_TAIL_NODE_UTS,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_UTS * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_CHILD_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_TAIL_NODE_UTS > trie.length) {\n trie = grow(trie, child + TRIE_TAIL_NODE_UTS);\n }\n trie[TRIE_SIZE_IDX] += TRIE_TAIL_NODE_UTS;\n // Attach and initialize node\n trie[index + TRIE_CHILD_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array {\n const minSize = TRIE_HEADER_UTS;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n console.log(\"D\");\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_TAIL_NODE_CHILDREN_UTS;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_CHILD_UTS;\n bi += TRIE_CHILD_UTS;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_CHILD_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_RED_UTS > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_RED_UTS);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_RED_UTS;\n // Add new redirect\n tries[at][li + TRIE_RED_ID_IDX] = rt;\n tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_CHILD_UTS;\n bi += TRIE_CHILD_UTS;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, 0, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childKey, childPtr] = stack[top];\n\n // Check if end of children array\n if (childKey >= TRIE_TAIL_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n ++stack[top][1];\n stack[top][2] += TRIE_CHILD_UTS;\n\n // If just reached node\n if (childKey === 0) {\n // Check if the node has a value\n const nodeIndex = childPtr - TRIE_NODE_CHILDREN_IDX;\n const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print the node's value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n }\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX];\n if (childI !== TRIE_NULL) {\n // Resolve child if redirect\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX];\n trieI = childTrieI;\n }\n // Add the child to the stack\n key[top] = childKey + UTF8_B0_MIN;\n stack[++top] = [trieI, 0, childI + TRIE_NODE_CHILDREN_IDX];\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/utf8Trie\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const numVals = MAX_STATIONS * maxWorkers + 1;\n let bpe = Uint32Array.BYTES_PER_ELEMENT;\n const counts = new Uint32Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Int16Array.BYTES_PER_ELEMENT;\n const maxes = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n const mins = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Float64Array.BYTES_PER_ELEMENT;\n const sums = new Float64Array(new SharedArrayBuffer(bpe * numVals));\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n counts,\n end,\n filePath,\n id,\n maxes,\n mins,\n start,\n sums,\n } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n tries[res.id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 1; i < maxWorkers; ++i) {\n mergeLeft(tries, 0, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(ai: number, bi: number): void {\n counts[ai] += counts[bi];\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n mins[ai] = Math.min(mins[ai], mins[bi]);\n sums[ai] += sums[bi];\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi] / counts[vi]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: WorkerRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n counts[index] = 1;\n maxes[index] = temp;\n mins[index] = temp;\n sums[index] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n ++counts[index];\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n sums[index] += temp;\n }\n\n return { id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n return ++min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [res.trie.buffer]);\n });\n}\n"],"names":["open","at","bt","run","Worker","createWriteStream","createReadStream","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN } from \"./utf8\";\n\n// Trie static properties\n\n/**\n * Represents null / undefined.\n */\nexport const TRIE_NULL = 0;\n\n/**\n * The minimum size a trie.\n */\nexport const MIN_TRIE_SIZE = 524288; // 2 MiB\n\n/**\n * The default growth factor for growing the size of a trie.\n */\nexport const TRIE_GROWTH_FACTOR = 1.618; // ~phi\n\n/**\n * All trie properties are represented by 32 bits (4 bytes).\n */\nexport const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT;\n\n// Trie child pointer properties\n\nexport const TRIE_CHILD_IDX_IDX = 0;\nexport const TRIE_CHILD_IDX_MEM = 1;\n\nexport const TRIE_CHILD_MEM = TRIE_CHILD_IDX_MEM;\n\n// Trie redirect pointer properties\n\nexport const TRIE_RED_ID_IDX = 0;\nexport const TRIE_RED_ID_MEM = 1;\n\nexport const TRIE_RED_VALUE_IDX_IDX = 1;\nexport const TRIE_RED_VALUE_IDX_MEM = 1;\n\nexport const TRIE_RED_MEM = TRIE_RED_ID_MEM + TRIE_RED_VALUE_IDX_MEM;\n\n// Trie node properties\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\nexport const TRIE_NODE_VALUE_IDX_IDX = 1;\nexport const TRIE_NODE_VALUE_IDX_MEM = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_CHILD_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_IDX_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie properties\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_HEADER_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n MIN_TRIE_SIZE,\n TRIE_CHILD_MEM,\n TRIE_CHILD_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_HEADER_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_RED_MEM,\n TRIE_RED_VALUE_IDX_IDX,\n TRIE_RED_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_MEM * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_CHILD_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach and initialize node\n trie[index + TRIE_CHILD_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array {\n const minSize = TRIE_HEADER_MEM;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_CHILD_MEM;\n bi += TRIE_CHILD_MEM;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_CHILD_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_RED_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_RED_MEM);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_RED_MEM;\n // Add new redirect\n tries[at][li + TRIE_RED_ID_IDX] = rt;\n tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_CHILD_MEM;\n bi += TRIE_CHILD_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_CHILD_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_B0_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/utf8Trie\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const numVals = MAX_STATIONS * maxWorkers + 1;\n let bpe = Uint32Array.BYTES_PER_ELEMENT;\n const counts = new Uint32Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Int16Array.BYTES_PER_ELEMENT;\n const maxes = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n const mins = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Float64Array.BYTES_PER_ELEMENT;\n const sums = new Float64Array(new SharedArrayBuffer(bpe * numVals));\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n counts,\n end,\n filePath,\n id,\n maxes,\n mins,\n start,\n sums,\n } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n tries[res.id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 1; i < maxWorkers; ++i) {\n mergeLeft(tries, 0, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(ai: number, bi: number): void {\n counts[ai] += counts[bi];\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n mins[ai] = Math.min(mins[ai], mins[bi]);\n sums[ai] += sums[bi];\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi] / counts[vi]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: WorkerRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n counts[index] = 1;\n maxes[index] = temp;\n mins[index] = temp;\n sums[index] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n ++counts[index];\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n sums[index] += temp;\n }\n\n return { id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n return ++min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [res.trie.buffer]);\n });\n}\n"],"names":["open","at","bt","run","Worker","createWriteStream","createReadStream","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","runWorker"],"mappings":";;;;;;;;;AAQO,MAAM,YAAe,GAAA,GAAA,CAAA;AAKrB,MAAM,oBAAuB,GAAA,GAAA,CAAA;AAW7B,MAAM,aAAgB,GAAA,GAAA;;ACnBtB,MAAM,UAAa,GAAA,EAAA,CAAA;AAKnB,MAAM,YAAe,GAAA,EAAA,CAAA;AAUrB,MAAM,cAAiB,GAAA,EAAA,CAAA;AAKvB,MAAM,SAAY,GAAA,EAAA,CAAA;AAWlB,MAAM,WAAc,GAAA,EAAA,CAAA;AAuBpB,MAAM,cAAiB,GAAA,GAAA,CAAA;AAMjB,MAAA,cAAA,GAAiB,iBAAiB,WAAc,GAAA,CAAA;;AC5DtD,MAAM,mBAAsB,GAAA,KAAA,CAAA;AAK5B,MAAM,mBAAsB,GAAA,OAAA,CAAA;AAK5B,MAAM,mBAAsB,GAAA,OAAA,CAAA;AAM5B,MAAM,qBAAwB,GAAA,MAAA,CAAA;AAK9B,MAAM,cAAiB,GAAA,mBAAA,CAAA;AAOvB,MAAM,eAAe,EAAK,GAAA,SAAA,CAAA;AAK1B,MAAM,gBAAgB,GAAM,GAAA,SAAA;;ACnC5B,MAAM,WAAc,GAAA,CAAA,CAAA;AAKpB,MAAM,WAAc,GAAA,GAAA;;ACUX,SAAA,KAAA,CAAM,KAAe,EAAA,GAAA,EAAa,GAAqB,EAAA;AACrE,EAAA,OAAO,KAAQ,GAAA,GAAA,GAAO,KAAS,IAAA,GAAA,GAAM,QAAQ,GAAO,GAAA,GAAA,CAAA;AACtD,CAAA;AAoBA,eAAsB,aACpB,CAAA,QAAA,EACA,MACA,EAAA,aAAA,EACA,UAAU,CACmB,EAAA;AAE7B,EAAM,MAAA,IAAA,GAAO,MAAMA,aAAA,CAAK,QAAQ,CAAA,CAAA;AAChC,EAAI,IAAA;AAEF,IAAA,MAAM,IAAQ,GAAA,CAAA,MAAM,IAAK,CAAA,IAAA,EAAQ,EAAA,IAAA,CAAA;AAEjC,IAAM,MAAA,SAAA,GAAY,KAAK,GAAI,CAAA,OAAA,EAAS,KAAK,KAAM,CAAA,IAAA,GAAO,MAAM,CAAC,CAAA,CAAA;AAE7D,IAAM,MAAA,MAAA,GAAS,MAAO,CAAA,WAAA,CAAY,aAAa,CAAA,CAAA;AAC/C,IAAA,MAAM,SAA6B,EAAC,CAAA;AAEpC,IAAA,IAAI,KAAQ,GAAA,CAAA,CAAA;AACZ,IAAA,KAAA,IAAS,GAAM,GAAA,SAAA,EAAW,GAAM,GAAA,IAAA,EAAM,OAAO,SAAW,EAAA;AAEtD,MAAA,MAAM,MAAM,MAAM,IAAA,CAAK,KAAK,MAAQ,EAAA,CAAA,EAAG,eAAe,GAAG,CAAA,CAAA;AAEzD,MAAM,MAAA,OAAA,GAAU,MAAO,CAAA,OAAA,CAAQ,YAAY,CAAA,CAAA;AAE3C,MAAA,IAAI,OAAW,IAAA,CAAA,IAAK,OAAU,GAAA,GAAA,CAAI,SAAW,EAAA;AAE3C,QAAA,GAAA,IAAO,OAAU,GAAA,CAAA,CAAA;AAEjB,QAAA,MAAA,CAAO,IAAK,CAAA,CAAC,KAAO,EAAA,GAAG,CAAC,CAAA,CAAA;AAExB,QAAQ,KAAA,GAAA,GAAA,CAAA;AAAA,OACV;AAAA,KACF;AAEA,IAAA,IAAI,QAAQ,IAAM,EAAA;AAChB,MAAA,MAAA,CAAO,IAAK,CAAA,CAAC,KAAO,EAAA,IAAI,CAAC,CAAA,CAAA;AAAA,KAC3B;AAEA,IAAO,OAAA,MAAA,CAAA;AAAA,GACP,SAAA;AAEA,IAAA,MAAM,KAAK,KAAM,EAAA,CAAA;AAAA,GACnB;AACF,CAAA;AASO,SAAS,iBAAiB,IAAsB,EAAA;AAErD,EAAQ,IAAA,IAAA,qBAAA,CAAA;AAER,EAAA,IAAA,GAAO,IAAK,CAAA,KAAA,CAAM,IAAK,CAAA,IAAA,CAAK,IAAI,CAAC,CAAA,CAAA;AAEjC,EAAA,IAAA,GAAO,CAAK,IAAA,IAAA,CAAA;AAEZ,EAAO,OAAA,KAAA,CAAM,IAAM,EAAA,mBAAA,EAAqB,mBAAmB,CAAA,CAAA;AAC7D;;AC9FO,MAAM,SAAY,GAAA,CAAA,CAAA;AAKlB,MAAM,aAAgB,GAAA,MAAA,CAAA;AAKtB,MAAM,kBAAqB,GAAA,KAAA,CAAA;AAS3B,MAAM,kBAAqB,GAAA,CAAA,CAAA;AAC3B,MAAM,kBAAqB,GAAA,CAAA,CAAA;AAE3B,MAAM,cAAiB,GAAA,kBAAA,CAAA;AAIvB,MAAM,eAAkB,GAAA,CAAA,CAAA;AACxB,MAAM,eAAkB,GAAA,CAAA,CAAA;AAExB,MAAM,sBAAyB,GAAA,CAAA,CAAA;AAC/B,MAAM,sBAAyB,GAAA,CAAA,CAAA;AAE/B,MAAM,eAAe,eAAkB,GAAA,sBAAA,CAAA;AAIvC,MAAM,gBAAmB,GAAA,CAAA,CAAA;AACzB,MAAM,gBAAmB,GAAA,CAAA,CAAA;AAEzB,MAAM,uBAA0B,GAAA,CAAA,CAAA;AAChC,MAAM,uBAA0B,GAAA,CAAA,CAAA;AAEhC,MAAM,sBAAyB,GAAA,CAAA,CAAA;AAC/B,MAAM,sBAAyB,GAAA,cAAA,CAAA;AAC/B,MAAM,yBAAyB,cAAiB,GAAA,sBAAA,CAAA;AAE1C,MAAA,aAAA,GACX,mBAAmB,uBAA0B,GAAA,sBAAA,CAAA;AAIxC,MAAM,aAAgB,GAAA,CAAA,CAAA;AACtB,MAAM,aAAgB,GAAA,CAAA,CAAA;AAEtB,MAAM,aAAgB,GAAA,CAAA,CAAA;AACtB,MAAM,aAAgB,GAAA,aAAA,CAAA;AAEtB,MAAM,cAAc,aAAgB,GAAA,gBAAA,CAAA;AACpC,MAAM,kBAAkB,aAAgB,GAAA,aAAA;;ACzCxC,SAAS,GACd,CAAA,IAAA,EACA,GACA,EAAA,GAAA,EACA,GACsB,EAAA;AACtB,EAAA,IAAI,KAAQ,GAAA,aAAA,CAAA;AACZ,EAAA,OAAO,MAAM,GAAK,EAAA;AAChB,IAAA,KAAA,IACE,sBAAyB,GAAA,cAAA,IAAkB,GAAI,CAAA,GAAA,EAAK,CAAI,GAAA,WAAA,CAAA,CAAA;AAC1D,IAAI,IAAA,KAAA,GAAQ,IAAK,CAAA,KAAA,GAAQ,kBAAkB,CAAA,CAAA;AAC3C,IAAA,IAAI,UAAU,SAAW,EAAA;AAEvB,MAAA,KAAA,GAAQ,KAAK,aAAa,CAAA,CAAA;AAC1B,MAAI,IAAA,KAAA,GAAQ,aAAgB,GAAA,IAAA,CAAK,MAAQ,EAAA;AACvC,QAAO,IAAA,GAAA,IAAA,CAAK,IAAM,EAAA,KAAA,GAAQ,aAAa,CAAA,CAAA;AAAA,OACzC;AACA,MAAA,IAAA,CAAK,aAAa,CAAK,IAAA,aAAA,CAAA;AAEvB,MAAK,IAAA,CAAA,KAAA,GAAQ,kBAAkB,CAAI,GAAA,KAAA,CAAA;AACnC,MAAA,IAAA,CAAK,KAAQ,GAAA,gBAAgB,CAAI,GAAA,IAAA,CAAK,WAAW,CAAA,CAAA;AAAA,KACnD;AACA,IAAQ,KAAA,GAAA,KAAA,CAAA;AAAA,GACV;AAEA,EAAO,OAAA,CAAC,MAAM,KAAK,CAAA,CAAA;AACrB,CAAA;AAEO,SAAS,UAAW,CAAA,EAAA,GAAK,CAAG,EAAA,IAAA,GAAO,aAA2B,EAAA;AACnE,EAAA,MAAM,OAAU,GAAA,eAAA,CAAA;AAChB,EAAA,MAAM,OAAO,IAAI,UAAA,CAAW,KAAK,GAAI,CAAA,OAAA,EAAS,IAAI,CAAC,CAAA,CAAA;AACnD,EAAA,IAAA,CAAK,aAAa,CAAI,GAAA,OAAA,CAAA;AACtB,EAAA,IAAA,CAAK,WAAW,CAAI,GAAA,EAAA,CAAA;AACpB,EAAO,OAAA,IAAA,CAAA;AACT,CAAA;AAEgB,SAAA,IAAA,CAAK,IAAkB,EAAA,OAAA,GAAU,CAAe,EAAA;AAC9D,EAAM,MAAA,MAAA,GAAS,KAAK,aAAa,CAAA,CAAA;AACjC,EAAA,OAAA,GAAU,KAAK,GAAI,CAAA,OAAA,EAAS,KAAK,IAAK,CAAA,MAAA,GAAS,kBAAkB,CAAC,CAAA,CAAA;AAClE,EAAM,MAAA,IAAA,GAAO,IAAI,UAAA,CAAW,OAAO,CAAA,CAAA;AACnC,EAAA,KAAA,IAAS,CAAI,GAAA,CAAA,EAAG,CAAI,GAAA,MAAA,EAAQ,EAAE,CAAG,EAAA;AAC/B,IAAK,IAAA,CAAA,CAAC,CAAI,GAAA,IAAA,CAAK,CAAC,CAAA,CAAA;AAAA,GAClB;AACA,EAAO,OAAA,IAAA,CAAA;AACT,CAAA;AAEO,SAAS,SACd,CAAA,KAAA,EACA,EACA,EAAA,EAAA,EACA,OACM,EAAA;AACN,EAAA,MAAM,KAA4C,GAAA;AAAA,IAChD,CAAC,EAAA,EAAI,aAAe,EAAA,EAAA,EAAI,aAAa,CAAA;AAAA,GACvC,CAAA;AAEA,EAAG,GAAA;AACD,IAAA,MAAM,IAAI,KAAM,CAAA,MAAA,CAAA;AAChB,IAAA,KAAA,IAAS,CAAI,GAAA,CAAA,EAAG,CAAI,GAAA,CAAA,EAAG,EAAE,CAAG,EAAA;AAC1B,MAAA,IAAI,CAACC,GAAI,EAAA,EAAA,EAAIC,KAAI,EAAE,CAAA,GAAI,MAAM,CAAC,CAAA,CAAA;AAG9B,MAAA,MAAM,GAAM,GAAA,KAAA,CAAMA,GAAE,CAAA,CAAE,KAAK,uBAAuB,CAAA,CAAA;AAClD,MAAA,IAAI,QAAQ,SAAW,EAAA;AAErB,QAAA,MAAM,GAAM,GAAA,KAAA,CAAMD,GAAE,CAAA,CAAE,KAAK,uBAAuB,CAAA,CAAA;AAClD,QAAA,IAAI,QAAQ,SAAW,EAAA;AACrB,UAAA,OAAA,CAAQ,KAAK,GAAG,CAAA,CAAA;AAAA,SACX,MAAA;AACL,UAAA,KAAA,CAAMA,GAAE,CAAA,CAAE,EAAK,GAAA,uBAAuB,CAAI,GAAA,GAAA,CAAA;AAAA,SAC5C;AAAA,OACF;AAGA,MAAM,EAAA,IAAA,sBAAA,CAAA;AACN,MAAM,EAAA,IAAA,sBAAA,CAAA;AAGN,MAAA,MAAM,KAAK,EAAK,GAAA,sBAAA,CAAA;AAChB,MAAA,OAAO,KAAK,EAAI,EAAA;AAEd,QAAA,IAAI,EAAK,GAAA,KAAA,CAAMC,GAAE,CAAA,CAAE,KAAK,kBAAkB,CAAA,CAAA;AAC1C,QAAA,IAAI,OAAO,SAAW,EAAA;AAEpB,UAAM,EAAA,IAAA,cAAA,CAAA;AACN,UAAM,EAAA,IAAA,cAAA,CAAA;AACN,UAAA,SAAA;AAAA,SACF;AAGA,QAAA,MAAM,EAAK,GAAA,KAAA,CAAMA,GAAE,CAAA,CAAE,KAAK,gBAAgB,CAAA,CAAA;AAC1C,QAAA,IAAIA,QAAO,EAAI,EAAA;AACb,UAAA,EAAA,GAAK,KAAMA,CAAAA,GAAE,CAAE,CAAA,EAAA,GAAK,sBAAsB,CAAA,CAAA;AAAA,SAC5C;AAGA,QAAA,IAAI,EAAK,GAAA,KAAA,CAAMD,GAAE,CAAA,CAAE,KAAK,kBAAkB,CAAA,CAAA;AAC1C,QAAA,IAAI,OAAO,SAAW,EAAA;AAEpB,UAAK,EAAA,GAAA,KAAA,CAAMA,GAAE,CAAA,CAAE,aAAa,CAAA,CAAA;AAC5B,UAAA,IAAI,EAAK,GAAA,YAAA,GAAe,KAAMA,CAAAA,GAAE,EAAE,MAAQ,EAAA;AACxC,YAAA,KAAA,CAAMA,GAAE,CAAI,GAAA,IAAA,CAAK,MAAMA,GAAE,CAAA,EAAG,KAAK,YAAY,CAAA,CAAA;AAAA,WAC/C;AACA,UAAMA,KAAAA,CAAAA,GAAE,CAAE,CAAA,aAAa,CAAK,IAAA,YAAA,CAAA;AAE5B,UAAA,KAAA,CAAMA,GAAE,CAAA,CAAE,EAAK,GAAA,eAAe,CAAI,GAAA,EAAA,CAAA;AAClC,UAAA,KAAA,CAAMA,GAAE,CAAA,CAAE,EAAK,GAAA,sBAAsB,CAAI,GAAA,EAAA,CAAA;AAAA,SACpC,MAAA;AAEL,UAAA,MAAM,EAAK,GAAA,KAAA,CAAMA,GAAE,CAAA,CAAE,KAAK,gBAAgB,CAAA,CAAA;AAC1C,UAAA,IAAIA,QAAO,EAAI,EAAA;AACb,YAAA,EAAA,GAAK,KAAMA,CAAAA,GAAE,CAAE,CAAA,EAAA,GAAK,sBAAsB,CAAA,CAAA;AAAA,WAC5C;AAEA,UAAA,KAAA,CAAM,KAAK,CAAC,EAAA,EAAI,EAAI,EAAA,EAAA,EAAI,EAAE,CAAC,CAAA,CAAA;AAAA,SAC7B;AAGA,QAAM,EAAA,IAAA,cAAA,CAAA;AACN,QAAM,EAAA,IAAA,cAAA,CAAA;AAAA,OACR;AAAA,KACF;AACA,IAAM,KAAA,CAAA,MAAA,CAAO,GAAG,CAAC,CAAA,CAAA;AAAA,GACnB,QAAS,MAAM,MAAS,GAAA,CAAA,EAAA;AAC1B,CAAA;AAEO,SAAS,MACd,KACA,EAAA,GAAA,EACA,WACA,MACA,EAAA,SAAA,GAAY,IACZ,UAMM,EAAA;AACN,EAAA,MAAM,KAAoC,GAAA,IAAI,KAAM,CAAA,GAAA,CAAI,SAAS,CAAC,CAAA,CAAA;AAClE,EAAA,KAAA,CAAM,CAAC,CAAI,GAAA,CAAC,SAAW,EAAA,aAAA,GAAgB,wBAAwB,CAAC,CAAA,CAAA;AAEhE,EAAA,IAAI,GAAM,GAAA,CAAA,CAAA;AACV,EAAA,IAAI,IAAO,GAAA,KAAA,CAAA;AACX,EAAG,GAAA;AACD,IAAA,IAAI,CAAC,KAAO,EAAA,QAAA,EAAU,QAAQ,CAAA,GAAI,MAAM,GAAG,CAAA,CAAA;AAG3C,IAAA,IAAI,YAAY,sBAAwB,EAAA;AACtC,MAAE,EAAA,GAAA,CAAA;AACF,MAAA,SAAA;AAAA,KACF;AAGA,IAAM,KAAA,CAAA,GAAG,CAAE,CAAA,CAAC,CAAK,IAAA,cAAA,CAAA;AACjB,IAAE,EAAA,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,CAAA,CAAA;AAGd,IAAA,IAAI,MAAS,GAAA,KAAA,CAAM,KAAK,CAAA,CAAE,WAAW,kBAAkB,CAAA,CAAA;AACvD,IAAA,IAAI,WAAW,SAAW,EAAA;AACxB,MAAA,SAAA;AAAA,KACF;AAGA,IAAA,MAAM,UAAa,GAAA,KAAA,CAAM,KAAK,CAAA,CAAE,SAAS,gBAAgB,CAAA,CAAA;AACzD,IAAA,IAAI,UAAU,UAAY,EAAA;AACxB,MAAA,MAAA,GAAS,KAAM,CAAA,KAAK,CAAE,CAAA,MAAA,GAAS,sBAAsB,CAAA,CAAA;AACrD,MAAQ,KAAA,GAAA,UAAA,CAAA;AAAA,KACV;AAGA,IAAI,GAAA,CAAA,GAAG,IAAI,QAAW,GAAA,WAAA,CAAA;AACtB,IAAA,KAAA,CAAM,EAAE,GAAG,CAAA,GAAI,CAAC,KAAO,EAAA,MAAA,GAAS,wBAAwB,CAAC,CAAA,CAAA;AAGzD,IAAA,MAAM,UAAa,GAAA,KAAA,CAAM,KAAK,CAAA,CAAE,SAAS,uBAAuB,CAAA,CAAA;AAChE,IAAA,IAAI,eAAe,SAAW,EAAA;AAE5B,MAAA,IAAI,IAAM,EAAA;AACR,QAAA,MAAA,CAAO,MAAM,SAAS,CAAA,CAAA;AAAA,OACxB;AACA,MAAO,IAAA,GAAA,IAAA,CAAA;AACP,MAAW,UAAA,CAAA,MAAA,EAAQ,GAAK,EAAA,GAAA,EAAK,UAAU,CAAA,CAAA;AAAA,KACzC;AAAA,WACO,GAAO,IAAA,CAAA,EAAA;AAClB;;ACjMA,eAAsBE,KACpB,CAAA,QAAA,EACA,UACA,EAAA,UAAA,EACA,UAAU,EACK,EAAA;AAEf,EAAa,UAAA,GAAA,KAAA,CAAM,UAAY,EAAA,WAAA,EAAa,WAAW,CAAA,CAAA;AAGvD,EAAA,MAAM,SAAS,MAAM,aAAA;AAAA,IACnB,QAAA;AAAA,IACA,UAAA;AAAA,IACA,aAAA;AAAA,IACA,cAAA;AAAA,GACF,CAAA;AAGA,EAAA,UAAA,GAAa,MAAO,CAAA,MAAA,CAAA;AAGpB,EAAM,MAAA,OAAA,GAAU,eAAe,UAAa,GAAA,CAAA,CAAA;AAC5C,EAAA,IAAI,MAAM,WAAY,CAAA,iBAAA,CAAA;AACtB,EAAA,MAAM,SAAS,IAAI,WAAA,CAAY,IAAI,iBAAkB,CAAA,GAAA,GAAM,OAAO,CAAC,CAAA,CAAA;AACnE,EAAA,GAAA,GAAM,UAAW,CAAA,iBAAA,CAAA;AACjB,EAAA,MAAM,QAAQ,IAAI,UAAA,CAAW,IAAI,iBAAkB,CAAA,GAAA,GAAM,OAAO,CAAC,CAAA,CAAA;AACjE,EAAA,MAAM,OAAO,IAAI,UAAA,CAAW,IAAI,iBAAkB,CAAA,GAAA,GAAM,OAAO,CAAC,CAAA,CAAA;AAChE,EAAA,GAAA,GAAM,YAAa,CAAA,iBAAA,CAAA;AACnB,EAAA,MAAM,OAAO,IAAI,YAAA,CAAa,IAAI,iBAAkB,CAAA,GAAA,GAAM,OAAO,CAAC,CAAA,CAAA;AAClE,EAAM,MAAA,KAAA,GAAsB,IAAI,KAAA,CAAM,UAAU,CAAA,CAAA;AAGhD,EAAM,MAAA,OAAA,GAAU,IAAI,KAAA,CAAc,UAAU,CAAA,CAAA;AAC5C,EAAA,KAAA,IAAS,CAAI,GAAA,CAAA,EAAG,CAAI,GAAA,UAAA,EAAY,EAAE,CAAG,EAAA;AACnC,IAAM,MAAA,MAAA,GAAS,IAAIC,0BAAA,CAAO,UAAU,CAAA,CAAA;AACpC,IAAO,MAAA,CAAA,EAAA,CAAG,OAAS,EAAA,CAAC,GAAQ,KAAA;AAC1B,MAAM,MAAA,GAAA,CAAA;AAAA,KACP,CAAA,CAAA;AACD,IAAO,MAAA,CAAA,EAAA,CAAG,cAAgB,EAAA,CAAC,GAAQ,KAAA;AACjC,MAAM,MAAA,GAAA,CAAA;AAAA,KACP,CAAA,CAAA;AACD,IAAO,MAAA,CAAA,EAAA,CAAG,MAAQ,EAAA,CAAC,IAAS,KAAA;AAC1B,MAAI,IAAA,IAAA,GAAO,CAAK,IAAA,IAAA,GAAO,CAAG,EAAA;AACxB,QAAA,MAAM,IAAI,KAAM,CAAA,CAAA,OAAA,EAAU,OAAO,QAAQ,CAAA,kBAAA,EAAqB,IAAI,CAAE,CAAA,CAAA,CAAA;AAAA,OACtE;AAAA,KACD,CAAA,CAAA;AACD,IAAA,OAAA,CAAQ,CAAC,CAAI,GAAA,MAAA,CAAA;AAAA,GACf;AAGA,EAAM,MAAA,KAAA,GAAQ,IAAI,KAAA,CAA+B,UAAU,CAAA,CAAA;AAC3D,EAAA,KAAA,IAAS,CAAI,GAAA,CAAA,EAAG,CAAI,GAAA,UAAA,EAAY,EAAE,CAAG,EAAA;AACnC,IAAA,MAAM,EAAK,GAAA,CAAA,CAAA;AACX,IAAM,MAAA,MAAA,GAAS,QAAQ,CAAC,CAAA,CAAA;AACxB,IAAA,MAAM,CAAC,KAAA,EAAO,GAAG,CAAA,GAAI,OAAO,CAAC,CAAA,CAAA;AAC7B,IAAA,KAAA,CAAM,CAAC,CAAA,GAAI,IAAI,OAAA,CAAQ,CAAC,OAAY,KAAA;AAClC,MAAO,MAAA,CAAA,IAAA,CAAK,WAAW,OAAO,CAAA,CAAA;AAC9B,MAAA,MAAA,CAAO,WAAY,CAAA;AAAA,QACjB,MAAA;AAAA,QACA,GAAA;AAAA,QACA,QAAA;AAAA,QACA,EAAA;AAAA,QACA,KAAA;AAAA,QACA,IAAA;AAAA,QACA,KAAA;AAAA,QACA,IAAA;AAAA,OACgB,CAAA,CAAA;AAAA,KACnB,CAAA,CAAA;AAAA,GACH;AAGA,EAAA,WAAA,MAAiB,OAAO,KAAO,EAAA;AAC7B,IAAM,KAAA,CAAA,GAAA,CAAI,EAAE,CAAA,GAAI,GAAI,CAAA,IAAA,CAAA;AAAA,GACtB;AAGA,EAAA,KAAA,IAAS,CAAI,GAAA,CAAA,EAAG,CAAI,GAAA,UAAA,EAAY,EAAE,CAAG,EAAA;AACnC,IAAM,MAAA,OAAA,CAAQ,CAAC,CAAA,CAAE,SAAU,EAAA,CAAA;AAAA,GAC7B;AAGA,EAAA,KAAA,IAAS,CAAI,GAAA,CAAA,EAAG,CAAI,GAAA,UAAA,EAAY,EAAE,CAAG,EAAA;AACnC,IAAU,SAAA,CAAA,KAAA,EAAO,CAAG,EAAA,CAAA,EAAG,aAAa,CAAA,CAAA;AAAA,GACtC;AAGA,EAAM,MAAA,GAAA,GAAMC,0BAAkB,OAAS,EAAA;AAAA,IACrC,EAAI,EAAA,OAAA,CAAQ,MAAS,GAAA,CAAA,GAAI,CAAI,GAAA,KAAA,CAAA;AAAA,IAC7B,KAAO,EAAA,GAAA;AAAA,IACP,aAAe,EAAA,mBAAA;AAAA,GAChB,CAAA,CAAA;AACD,EAAM,MAAA,MAAA,GAAS,MAAO,CAAA,WAAA,CAAY,oBAAoB,CAAA,CAAA;AACtD,EAAA,GAAA,CAAI,MAAM,GAAG,CAAA,CAAA;AACb,EAAA,KAAA,CAAM,KAAO,EAAA,MAAA,EAAQ,CAAG,EAAA,GAAA,EAAK,MAAM,YAAY,CAAA,CAAA;AAC/C,EAAA,GAAA,CAAI,IAAI,KAAK,CAAA,CAAA;AAEb,EAAS,SAAA,aAAA,CAAc,IAAY,EAAkB,EAAA;AACnD,IAAO,MAAA,CAAA,EAAE,CAAK,IAAA,MAAA,CAAO,EAAE,CAAA,CAAA;AACvB,IAAM,KAAA,CAAA,EAAE,IAAI,IAAK,CAAA,GAAA,CAAI,MAAM,EAAE,CAAA,EAAG,KAAM,CAAA,EAAE,CAAC,CAAA,CAAA;AACzC,IAAK,IAAA,CAAA,EAAE,IAAI,IAAK,CAAA,GAAA,CAAI,KAAK,EAAE,CAAA,EAAG,IAAK,CAAA,EAAE,CAAC,CAAA,CAAA;AACtC,IAAK,IAAA,CAAA,EAAE,CAAK,IAAA,IAAA,CAAK,EAAE,CAAA,CAAA;AAAA,GACrB;AAEA,EAAA,SAAS,YACP,CAAA,MAAA,EACA,IACA,EAAA,OAAA,EACA,EACM,EAAA;AACN,IAAM,MAAA,GAAA,GAAM,KAAK,KAAM,CAAA,IAAA,CAAK,EAAE,CAAI,GAAA,MAAA,CAAO,EAAE,CAAC,CAAA,CAAA;AAC5C,IAAA,MAAA,CAAO,MAAM,IAAK,CAAA,QAAA,CAAS,MAAQ,EAAA,CAAA,EAAG,OAAO,CAAC,CAAA,CAAA;AAC9C,IAAA,MAAA,CAAO,MAAM,GAAG,CAAA,CAAA;AAChB,IAAA,MAAA,CAAO,OAAO,IAAK,CAAA,EAAE,IAAI,EAAI,EAAA,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAA;AACvC,IAAA,MAAA,CAAO,MAAM,GAAG,CAAA,CAAA;AAChB,IAAA,MAAA,CAAO,KAAO,CAAA,CAAA,GAAA,GAAM,EAAI,EAAA,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAA;AAClC,IAAA,MAAA,CAAO,MAAM,GAAG,CAAA,CAAA;AAChB,IAAA,MAAA,CAAO,OAAO,KAAM,CAAA,EAAE,IAAI,EAAI,EAAA,OAAA,CAAQ,CAAC,CAAC,CAAA,CAAA;AAAA,GAC1C;AACF;;ACxHA,eAAsB,GAAI,CAAA;AAAA,EACxB,GAAA;AAAA,EACA,QAAA;AAAA,EACA,EAAA;AAAA,EACA,KAAA;AAAA;AAAA,EAEA,MAAA;AAAA,EACA,KAAA;AAAA,EACA,IAAA;AAAA,EACA,IAAA;AACF,CAA2C,EAAA;AAEzC,EAAA,IAAI,SAAS,GAAK,EAAA;AAChB,IAAA,OAAO,EAAE,EAAI,EAAA,IAAA,EAAM,UAAW,CAAA,EAAA,EAAI,CAAC,CAAE,EAAA,CAAA;AAAA,GACvC;AAGA,EAAI,IAAA,IAAA,GAAO,WAAW,EAAE,CAAA,CAAA;AACxB,EAAI,IAAA,QAAA,GAAW,KAAK,YAAe,GAAA,CAAA,CAAA;AACnC,EAAM,MAAA,MAAA,GAAS,MAAO,CAAA,WAAA,CAAY,aAAa,CAAA,CAAA;AAG/C,EAAM,MAAA,MAAA,GAASC,yBAAiB,QAAU,EAAA;AAAA,IACxC,KAAA;AAAA,IACA,KAAK,GAAM,GAAA,CAAA;AAAA,IACX,aAAA,EAAe,gBAAiB,CAAA,GAAA,GAAM,KAAK,CAAA;AAAA,GAC5C,CAAA,CAAA;AAGD,EAAA,IAAI,IAAO,GAAA,CAAA,CAAA;AACX,EAAA,IAAI,KAAQ,GAAA,CAAA,CAAA;AACZ,EAAI,IAAA,IAAA,CAAA;AACJ,EAAA,WAAA,MAAiB,SAAS,MAAQ,EAAA;AAEhC,IAAA,MAAM,IAAI,KAAM,CAAA,MAAA,CAAA;AAChB,IAAA,KAAA,IAAS,CAAI,GAAA,CAAA,EAAG,CAAI,GAAA,CAAA,EAAG,EAAE,CAAG,EAAA;AAC1B,MAAI,IAAA,KAAA,CAAM,CAAC,CAAA,KAAM,cAAgB,EAAA;AAE/B,QAAQ,KAAA,GAAA,IAAA,CAAA;AAAA,OACC,MAAA,IAAA,KAAA,CAAM,CAAC,CAAA,KAAM,YAAc,EAAA;AAEpC,QAAO,MAAA,CAAA,IAAA,EAAM,CAAI,GAAA,KAAA,CAAM,CAAC,CAAA,CAAA;AAAA,OACnB,MAAA;AAEL,QAAA,MAAM,KAAQ,GAAA,WAAA,CAAY,MAAQ,EAAA,KAAA,EAAO,IAAI,CAAA,CAAA;AAC7C,QAAO,IAAA,GAAA,CAAA,CAAA;AAEP,QAAA,CAAC,MAAM,IAAI,CAAA,GAAI,IAAI,IAAM,EAAA,MAAA,EAAQ,GAAG,KAAK,CAAA,CAAA;AAEzC,QAAA,IAAI,IAAK,CAAA,IAAA,GAAO,uBAAuB,CAAA,KAAM,SAAW,EAAA;AAEtD,UAAA,aAAA,CAAc,IAAK,CAAA,IAAA,GAAO,uBAAuB,CAAA,EAAG,KAAK,CAAA,CAAA;AAAA,SACpD,MAAA;AAEL,UAAK,IAAA,CAAA,IAAA,GAAO,uBAAuB,CAAI,GAAA,QAAA,CAAA;AACvC,UAAA,UAAA,CAAW,YAAY,KAAK,CAAA,CAAA;AAAA,SAC9B;AAAA,OACF;AAAA,KACF;AAAA,GACF;AAEA,EAAS,SAAA,UAAA,CAAW,OAAe,IAAoB,EAAA;AACrD,IAAA,MAAA,CAAO,KAAK,CAAI,GAAA,CAAA,CAAA;AAChB,IAAA,KAAA,CAAM,KAAK,CAAI,GAAA,IAAA,CAAA;AACf,IAAA,IAAA,CAAK,KAAK,CAAI,GAAA,IAAA,CAAA;AACd,IAAA,IAAA,CAAK,KAAK,CAAI,GAAA,IAAA,CAAA;AAAA,GAChB;AAEA,EAAS,SAAA,aAAA,CAAc,OAAe,IAAoB,EAAA;AACxD,IAAA,EAAE,OAAO,KAAK,CAAA,CAAA;AACd,IAAM,KAAA,CAAA,KAAK,IAAI,KAAM,CAAA,KAAK,KAAK,IAAO,GAAA,KAAA,CAAM,KAAK,CAAI,GAAA,IAAA,CAAA;AACrD,IAAK,IAAA,CAAA,KAAK,IAAI,IAAK,CAAA,KAAK,KAAK,IAAO,GAAA,IAAA,CAAK,KAAK,CAAI,GAAA,IAAA,CAAA;AAClD,IAAA,IAAA,CAAK,KAAK,CAAK,IAAA,IAAA,CAAA;AAAA,GACjB;AAEA,EAAO,OAAA,EAAE,IAAI,IAAK,EAAA,CAAA;AACpB,CAAA;AAEgB,SAAA,WAAA,CAAY,CAAW,EAAA,GAAA,EAAa,GAAqB,EAAA;AACvE,EAAI,IAAA,CAAA,CAAE,GAAG,CAAA,KAAM,UAAY,EAAA;AACzB,IAAO,OAAA,EAAE,GAAM,GAAA,CAAA,GAAI,GACf,GAAA,EAAE,EAAK,GAAA,CAAA,CAAE,GAAG,CAAA,GAAI,CAAE,CAAA,GAAA,GAAM,CAAC,CAAA,GAAI,YAC7B,CAAA,GAAA,EAAE,GAAM,GAAA,CAAA,CAAE,GAAG,CAAA,GAAI,EAAK,GAAA,CAAA,CAAE,GAAM,GAAA,CAAC,CAAI,GAAA,CAAA,CAAE,GAAM,GAAA,CAAC,CAAI,GAAA,aAAA,CAAA,CAAA;AAAA,GACtD;AACA,EAAO,OAAA,GAAA,GAAM,CAAI,GAAA,GAAA,GACb,EAAK,GAAA,CAAA,CAAE,GAAG,CAAI,GAAA,CAAA,CAAE,GAAM,GAAA,CAAC,CAAI,GAAA,YAAA,GAC3B,MAAM,CAAE,CAAA,GAAG,CAAI,GAAA,EAAA,GAAK,CAAE,CAAA,GAAA,GAAM,CAAC,CAAI,GAAA,CAAA,CAAE,GAAM,GAAA,CAAC,CAAI,GAAA,aAAA,CAAA;AACpD;;AC5FA,IAAIC,gCAAc,EAAA;AAChB,EAAM,MAAA,UAAA,GAAaC,sBAAc,CAAA,8LAAe,CAAA,CAAA;AAChD,EAAAC,KAAA,CAAQ,QAAQ,IAAK,CAAA,CAAC,CAAG,EAAA,UAAA,EAAYC,8BAAsB,CAAA,CAAA;AAC7D,CAAO,MAAA;AACL,EAAYC,8BAAA,CAAA,WAAA,CAAY,SAAW,EAAA,OAAO,GAAuB,KAAA;AAC/D,IAAM,MAAA,GAAA,GAAM,MAAMC,GAAA,CAAU,GAAG,CAAA,CAAA;AAC/B,IAAAD,8BAAA,CAAY,YAAY,GAAK,EAAA,CAAC,GAAI,CAAA,IAAA,CAAK,MAAM,CAAC,CAAA,CAAA;AAAA,GAC/C,CAAA,CAAA;AACH;;"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index b8cc44f..5405254 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -65,40 +65,40 @@ function getHighWaterMark(size) { const TRIE_NULL = 0; const MIN_TRIE_SIZE = 524288; const TRIE_GROWTH_FACTOR = 1.618; -const TRIE_TAIL_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN; const TRIE_CHILD_IDX_IDX = 0; -const TRIE_CHILD_IDX_UTS = 1; -const TRIE_CHILD_UTS = TRIE_CHILD_IDX_UTS; +const TRIE_CHILD_IDX_MEM = 1; +const TRIE_CHILD_MEM = TRIE_CHILD_IDX_MEM; const TRIE_RED_ID_IDX = 0; -const TRIE_RED_ID_UTS = 1; +const TRIE_RED_ID_MEM = 1; const TRIE_RED_VALUE_IDX_IDX = 1; -const TRIE_RED_VALUE_IDX_UTS = 1; -const TRIE_RED_UTS = TRIE_RED_ID_UTS + TRIE_RED_VALUE_IDX_UTS; +const TRIE_RED_VALUE_IDX_MEM = 1; +const TRIE_RED_MEM = TRIE_RED_ID_MEM + TRIE_RED_VALUE_IDX_MEM; const TRIE_NODE_ID_IDX = 0; -const TRIE_NODE_ID_UTS = 1; +const TRIE_NODE_ID_MEM = 1; const TRIE_NODE_VALUE_IDX_IDX = 1; -const TRIE_NODE_VALUE_IDX_UTS = 1; +const TRIE_NODE_VALUE_IDX_MEM = 1; const TRIE_NODE_CHILDREN_IDX = 2; -const TRIE_TAIL_NODE_CHILDREN_UTS = TRIE_CHILD_UTS * TRIE_TAIL_NODE_CHILDREN_LEN; -const TRIE_TAIL_NODE_UTS = TRIE_NODE_ID_UTS + TRIE_NODE_VALUE_IDX_UTS + TRIE_TAIL_NODE_CHILDREN_UTS; +const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN; +const TRIE_NODE_CHILDREN_MEM = TRIE_CHILD_MEM * TRIE_NODE_CHILDREN_LEN; +const TRIE_NODE_MEM = TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_IDX_MEM + TRIE_NODE_CHILDREN_MEM; const TRIE_SIZE_IDX = 0; -const TRIE_SIZE_UTS = 1; +const TRIE_SIZE_MEM = 1; const TRIE_ROOT_IDX = 1; -const TRIE_ROOT_UTS = TRIE_TAIL_NODE_UTS; +const TRIE_ROOT_MEM = TRIE_NODE_MEM; const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX; -const TRIE_HEADER_UTS = TRIE_SIZE_UTS + TRIE_ROOT_UTS; +const TRIE_HEADER_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM; function add(trie, key, min, max) { let index = TRIE_ROOT_IDX; while (min < max) { - index += TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_UTS * (key[min++] - UTF8_B0_MIN); + index += TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_MEM * (key[min++] - UTF8_B0_MIN); let child = trie[index + TRIE_CHILD_IDX_IDX]; if (child === TRIE_NULL) { child = trie[TRIE_SIZE_IDX]; - if (child + TRIE_TAIL_NODE_UTS > trie.length) { - trie = grow(trie, child + TRIE_TAIL_NODE_UTS); + if (child + TRIE_NODE_MEM > trie.length) { + trie = grow(trie, child + TRIE_NODE_MEM); } - trie[TRIE_SIZE_IDX] += TRIE_TAIL_NODE_UTS; + trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM; trie[index + TRIE_CHILD_IDX_IDX] = child; trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX]; } @@ -107,14 +107,13 @@ function add(trie, key, min, max) { return [trie, index]; } function createTrie(id = 0, size = MIN_TRIE_SIZE) { - const minSize = TRIE_HEADER_UTS; + const minSize = TRIE_HEADER_MEM; const trie = new Int32Array(Math.max(minSize, size)); trie[TRIE_SIZE_IDX] = minSize; trie[TRIE_ID_IDX] = id; return trie; } function grow(trie, minSize = 0) { - console.log("D"); const length = trie[TRIE_SIZE_IDX]; minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR)); const next = new Int32Array(minSize); @@ -142,12 +141,12 @@ function mergeLeft(tries, at, bt, mergeFn) { } ai += TRIE_NODE_CHILDREN_IDX; bi += TRIE_NODE_CHILDREN_IDX; - const bn = bi + TRIE_TAIL_NODE_CHILDREN_UTS; + const bn = bi + TRIE_NODE_CHILDREN_MEM; while (bi < bn) { let ri = tries[bt2][bi + TRIE_CHILD_IDX_IDX]; if (ri === TRIE_NULL) { - ai += TRIE_CHILD_UTS; - bi += TRIE_CHILD_UTS; + ai += TRIE_CHILD_MEM; + bi += TRIE_CHILD_MEM; continue; } const rt = tries[bt2][ri + TRIE_NODE_ID_IDX]; @@ -157,10 +156,10 @@ function mergeLeft(tries, at, bt, mergeFn) { let li = tries[at2][ai + TRIE_CHILD_IDX_IDX]; if (li === TRIE_NULL) { li = tries[at2][TRIE_SIZE_IDX]; - if (li + TRIE_RED_UTS > tries[at2].length) { - tries[at2] = grow(tries[at2], li + TRIE_RED_UTS); + if (li + TRIE_RED_MEM > tries[at2].length) { + tries[at2] = grow(tries[at2], li + TRIE_RED_MEM); } - tries[at2][TRIE_SIZE_IDX] += TRIE_RED_UTS; + tries[at2][TRIE_SIZE_IDX] += TRIE_RED_MEM; tries[at2][li + TRIE_RED_ID_IDX] = rt; tries[at2][li + TRIE_RED_VALUE_IDX_IDX] = ri; } else { @@ -170,8 +169,8 @@ function mergeLeft(tries, at, bt, mergeFn) { } queue.push([lt, li, rt, ri]); } - ai += TRIE_CHILD_UTS; - bi += TRIE_CHILD_UTS; + ai += TRIE_CHILD_MEM; + bi += TRIE_CHILD_MEM; } } queue.splice(0, Q); @@ -179,37 +178,35 @@ function mergeLeft(tries, at, bt, mergeFn) { } function print(tries, key, trieIndex, stream, separator = "", callbackFn) { const stack = new Array(key.length + 1); - stack[0] = [trieIndex, 0, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX]; + stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0]; let top = 0; let tail = false; do { - let [trieI, childKey, childPtr] = stack[top]; - if (childKey >= TRIE_TAIL_NODE_CHILDREN_LEN) { + let [trieI, childPtr, numChild] = stack[top]; + if (numChild >= TRIE_NODE_CHILDREN_LEN) { --top; continue; } - ++stack[top][1]; - stack[top][2] += TRIE_CHILD_UTS; - if (childKey === 0) { - const nodeIndex = childPtr - TRIE_NODE_CHILDREN_IDX; - const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX]; - if (valueIndex !== TRIE_NULL) { - if (tail) { - stream.write(separator); - } - tail = true; - callbackFn(stream, key, top, valueIndex); - } - } + stack[top][1] += TRIE_CHILD_MEM; + ++stack[top][2]; let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX]; - if (childI !== TRIE_NULL) { - const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX]; - if (trieI !== childTrieI) { - childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX]; - trieI = childTrieI; + if (childI === TRIE_NULL) { + continue; + } + const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX]; + if (trieI !== childTrieI) { + childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX]; + trieI = childTrieI; + } + key[top] = numChild + UTF8_B0_MIN; + stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0]; + const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX_IDX]; + if (valueIndex !== TRIE_NULL) { + if (tail) { + stream.write(separator); } - key[top] = childKey + UTF8_B0_MIN; - stack[++top] = [trieI, 0, childI + TRIE_NODE_CHILDREN_IDX]; + tail = true; + callbackFn(stream, key, top, valueIndex); } } while (top >= 0); } diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index 13f7426..e2fc872 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1 +1 @@ -{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN, UTF8_BN_LEN } from \"./utf8\";\n\n// Trie static properties\n\n/**\n * Represents null / undefined.\n */\nexport const TRIE_NULL = 0;\n\n/**\n * The minimum size a trie.\n */\nexport const MIN_TRIE_SIZE = 524288; // 2 MiB\n\n/**\n * The default growth factor for growing the size of a trie.\n */\nexport const TRIE_GROWTH_FACTOR = 1.618; // ~phi\n\n/**\n * All trie properties are represented by 32 bits (4 bytes).\n */\nexport const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT;\n\nexport const TRIE_BODY_NODE_CHILDREN_LEN = UTF8_BN_LEN;\nexport const TRIE_TAIL_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\n\n// Trie child pointer properties\n\nexport const TRIE_CHILD_IDX_IDX = 0;\nexport const TRIE_CHILD_IDX_UTS = 1;\n\nexport const TRIE_CHILD_UTS = TRIE_CHILD_IDX_UTS;\n\n// Trie redirect pointer properties\n\nexport const TRIE_RED_ID_IDX = 0;\nexport const TRIE_RED_ID_UTS = 1;\n\nexport const TRIE_RED_VALUE_IDX_IDX = 1;\nexport const TRIE_RED_VALUE_IDX_UTS = 1;\n\nexport const TRIE_RED_UTS = TRIE_RED_ID_UTS + TRIE_RED_VALUE_IDX_UTS;\n\n// Trie node properties\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_UTS = 1;\n\nexport const TRIE_NODE_VALUE_IDX_IDX = 1;\nexport const TRIE_NODE_VALUE_IDX_UTS = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_BODY_NODE_CHILDREN_UTS =\n TRIE_CHILD_UTS * TRIE_BODY_NODE_CHILDREN_LEN;\nexport const TRIE_TAIL_NODE_CHILDREN_UTS =\n TRIE_CHILD_UTS * TRIE_TAIL_NODE_CHILDREN_LEN;\n\nexport const TRIE_BODY_NODE_UTS =\n TRIE_NODE_ID_UTS + TRIE_NODE_VALUE_IDX_UTS + TRIE_BODY_NODE_CHILDREN_UTS;\n\nexport const TRIE_TAIL_NODE_UTS =\n TRIE_NODE_ID_UTS + TRIE_NODE_VALUE_IDX_UTS + TRIE_TAIL_NODE_CHILDREN_UTS;\n\n// Trie properties\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_UTS = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_UTS = TRIE_TAIL_NODE_UTS;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_HEADER_UTS = TRIE_SIZE_UTS + TRIE_ROOT_UTS;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n MIN_TRIE_SIZE,\n TRIE_CHILD_UTS,\n TRIE_CHILD_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_HEADER_UTS,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_RED_UTS,\n TRIE_RED_VALUE_IDX_IDX,\n TRIE_RED_ID_IDX,\n TRIE_TAIL_NODE_CHILDREN_LEN,\n TRIE_TAIL_NODE_CHILDREN_UTS,\n TRIE_TAIL_NODE_UTS,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_UTS * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_CHILD_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_TAIL_NODE_UTS > trie.length) {\n trie = grow(trie, child + TRIE_TAIL_NODE_UTS);\n }\n trie[TRIE_SIZE_IDX] += TRIE_TAIL_NODE_UTS;\n // Attach and initialize node\n trie[index + TRIE_CHILD_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array {\n const minSize = TRIE_HEADER_UTS;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n console.log(\"D\");\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_TAIL_NODE_CHILDREN_UTS;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_CHILD_UTS;\n bi += TRIE_CHILD_UTS;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_CHILD_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_RED_UTS > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_RED_UTS);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_RED_UTS;\n // Add new redirect\n tries[at][li + TRIE_RED_ID_IDX] = rt;\n tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_CHILD_UTS;\n bi += TRIE_CHILD_UTS;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, 0, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childKey, childPtr] = stack[top];\n\n // Check if end of children array\n if (childKey >= TRIE_TAIL_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n ++stack[top][1];\n stack[top][2] += TRIE_CHILD_UTS;\n\n // If just reached node\n if (childKey === 0) {\n // Check if the node has a value\n const nodeIndex = childPtr - TRIE_NODE_CHILDREN_IDX;\n const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print the node's value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n }\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX];\n if (childI !== TRIE_NULL) {\n // Resolve child if redirect\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX];\n trieI = childTrieI;\n }\n // Add the child to the stack\n key[top] = childKey + UTF8_B0_MIN;\n stack[++top] = [trieI, 0, childI + TRIE_NODE_CHILDREN_IDX];\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/utf8Trie\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const numVals = MAX_STATIONS * maxWorkers + 1;\n let bpe = Uint32Array.BYTES_PER_ELEMENT;\n const counts = new Uint32Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Int16Array.BYTES_PER_ELEMENT;\n const maxes = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n const mins = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Float64Array.BYTES_PER_ELEMENT;\n const sums = new Float64Array(new SharedArrayBuffer(bpe * numVals));\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n counts,\n end,\n filePath,\n id,\n maxes,\n mins,\n start,\n sums,\n } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n tries[res.id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 1; i < maxWorkers; ++i) {\n mergeLeft(tries, 0, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(ai: number, bi: number): void {\n counts[ai] += counts[bi];\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n mins[ai] = Math.min(mins[ai], mins[bi]);\n sums[ai] += sums[bi];\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi] / counts[vi]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: WorkerRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n counts[index] = 1;\n maxes[index] = temp;\n mins[index] = temp;\n sums[index] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n ++counts[index];\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n sums[index] += temp;\n }\n\n return { id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n return ++min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [res.trie.buffer]);\n });\n}\n"],"names":["at","bt","run","runMain","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN } from \"./utf8\";\n\n// Trie static properties\n\n/**\n * Represents null / undefined.\n */\nexport const TRIE_NULL = 0;\n\n/**\n * The minimum size a trie.\n */\nexport const MIN_TRIE_SIZE = 524288; // 2 MiB\n\n/**\n * The default growth factor for growing the size of a trie.\n */\nexport const TRIE_GROWTH_FACTOR = 1.618; // ~phi\n\n/**\n * All trie properties are represented by 32 bits (4 bytes).\n */\nexport const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT;\n\n// Trie child pointer properties\n\nexport const TRIE_CHILD_IDX_IDX = 0;\nexport const TRIE_CHILD_IDX_MEM = 1;\n\nexport const TRIE_CHILD_MEM = TRIE_CHILD_IDX_MEM;\n\n// Trie redirect pointer properties\n\nexport const TRIE_RED_ID_IDX = 0;\nexport const TRIE_RED_ID_MEM = 1;\n\nexport const TRIE_RED_VALUE_IDX_IDX = 1;\nexport const TRIE_RED_VALUE_IDX_MEM = 1;\n\nexport const TRIE_RED_MEM = TRIE_RED_ID_MEM + TRIE_RED_VALUE_IDX_MEM;\n\n// Trie node properties\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\nexport const TRIE_NODE_VALUE_IDX_IDX = 1;\nexport const TRIE_NODE_VALUE_IDX_MEM = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_CHILD_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_IDX_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie properties\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_HEADER_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n MIN_TRIE_SIZE,\n TRIE_CHILD_MEM,\n TRIE_CHILD_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_HEADER_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_RED_MEM,\n TRIE_RED_VALUE_IDX_IDX,\n TRIE_RED_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_MEM * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_CHILD_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach and initialize node\n trie[index + TRIE_CHILD_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array {\n const minSize = TRIE_HEADER_MEM;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_CHILD_MEM;\n bi += TRIE_CHILD_MEM;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_CHILD_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_RED_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_RED_MEM);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_RED_MEM;\n // Add new redirect\n tries[at][li + TRIE_RED_ID_IDX] = rt;\n tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_CHILD_MEM;\n bi += TRIE_CHILD_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_CHILD_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_B0_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/utf8Trie\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const numVals = MAX_STATIONS * maxWorkers + 1;\n let bpe = Uint32Array.BYTES_PER_ELEMENT;\n const counts = new Uint32Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Int16Array.BYTES_PER_ELEMENT;\n const maxes = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n const mins = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Float64Array.BYTES_PER_ELEMENT;\n const sums = new Float64Array(new SharedArrayBuffer(bpe * numVals));\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n counts,\n end,\n filePath,\n id,\n maxes,\n mins,\n start,\n sums,\n } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n tries[res.id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 1; i < maxWorkers; ++i) {\n mergeLeft(tries, 0, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(ai: number, bi: number): void {\n counts[ai] += counts[bi];\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n mins[ai] = Math.min(mins[ai], mins[bi]);\n sums[ai] += sums[bi];\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi] / counts[vi]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: WorkerRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n counts[index] = 1;\n maxes[index] = temp;\n mins[index] = temp;\n sums[index] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n ++counts[index];\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n sums[index] += temp;\n }\n\n return { id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n return ++min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [res.trie.buffer]);\n });\n}\n"],"names":["at","bt","run","runMain","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts b/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts index 2882157..0ce8d8c 100644 --- a/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts +++ b/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts @@ -1,4 +1,4 @@ -import { UTF8_B0_2B_LEN, UTF8_BN_LEN } from "./utf8"; +import { UTF8_B0_2B_LEN } from "./utf8"; // Trie static properties @@ -22,9 +22,6 @@ export const TRIE_GROWTH_FACTOR = 1.618; // ~phi */ export const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT; -export const TRIE_BODY_NODE_CHILDREN_LEN = UTF8_BN_LEN; -export const TRIE_TAIL_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN; - // Trie child pointer properties export const TRIE_CHILD_IDX_IDX = 0; @@ -51,16 +48,11 @@ export const TRIE_NODE_VALUE_IDX_IDX = 1; export const TRIE_NODE_VALUE_IDX_MEM = 1; export const TRIE_NODE_CHILDREN_IDX = 2; -export const TRIE_BODY_NODE_CHILDREN_MEM = - TRIE_CHILD_MEM * TRIE_BODY_NODE_CHILDREN_LEN; -export const TRIE_TAIL_NODE_CHILDREN_MEM = - TRIE_CHILD_MEM * TRIE_TAIL_NODE_CHILDREN_LEN; - -export const TRIE_BODY_NODE_MEM = - TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_IDX_MEM + TRIE_BODY_NODE_CHILDREN_MEM; +export const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN; +export const TRIE_NODE_CHILDREN_MEM = TRIE_CHILD_MEM * TRIE_NODE_CHILDREN_LEN; -export const TRIE_TAIL_NODE_MEM = - TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_IDX_MEM + TRIE_TAIL_NODE_CHILDREN_MEM; +export const TRIE_NODE_MEM = + TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_IDX_MEM + TRIE_NODE_CHILDREN_MEM; // Trie properties @@ -68,7 +60,7 @@ export const TRIE_SIZE_IDX = 0; export const TRIE_SIZE_MEM = 1; export const TRIE_ROOT_IDX = 1; -export const TRIE_ROOT_MEM = TRIE_TAIL_NODE_MEM; +export const TRIE_ROOT_MEM = TRIE_NODE_MEM; export const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX; export const TRIE_HEADER_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM; diff --git a/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts b/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts index b65c59d..589b123 100644 --- a/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts +++ b/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts @@ -16,9 +16,9 @@ import { TRIE_RED_MEM, TRIE_RED_VALUE_IDX_IDX, TRIE_RED_ID_IDX, - TRIE_TAIL_NODE_CHILDREN_LEN, - TRIE_TAIL_NODE_CHILDREN_MEM, - TRIE_TAIL_NODE_MEM, + TRIE_NODE_MEM, + TRIE_NODE_CHILDREN_MEM, + TRIE_NODE_CHILDREN_LEN, } from "../constants/utf8Trie"; import { UTF8_B0_MIN } from "../constants/utf8"; @@ -36,10 +36,10 @@ export function add( if (child === TRIE_NULL) { // Allocate new node child = trie[TRIE_SIZE_IDX]; - if (child + TRIE_TAIL_NODE_MEM > trie.length) { - trie = grow(trie, child + TRIE_TAIL_NODE_MEM); + if (child + TRIE_NODE_MEM > trie.length) { + trie = grow(trie, child + TRIE_NODE_MEM); } - trie[TRIE_SIZE_IDX] += TRIE_TAIL_NODE_MEM; + trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM; // Attach and initialize node trie[index + TRIE_CHILD_IDX_IDX] = child; trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX]; @@ -59,7 +59,6 @@ export function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array { } export function grow(trie: Int32Array, minSize = 0): Int32Array { - console.log("D"); const length = trie[TRIE_SIZE_IDX]; minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR)); const next = new Int32Array(minSize); @@ -101,7 +100,7 @@ export function mergeLeft( bi += TRIE_NODE_CHILDREN_IDX; // Traverse right children - const bn = bi + TRIE_TAIL_NODE_CHILDREN_MEM; + const bn = bi + TRIE_NODE_CHILDREN_MEM; while (bi < bn) { // If right child is null let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX]; @@ -163,50 +162,49 @@ export function print( ) => void, ): void { const stack: [number, number, number][] = new Array(key.length + 1); - stack[0] = [trieIndex, 0, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX]; + stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0]; let top = 0; let tail = false; do { - let [trieI, childKey, childPtr] = stack[top]; + let [trieI, childPtr, numChild] = stack[top]; // Check if end of children array - if (childKey >= TRIE_TAIL_NODE_CHILDREN_LEN) { + if (numChild >= TRIE_NODE_CHILDREN_LEN) { --top; continue; } // Update stack top - ++stack[top][1]; - stack[top][2] += TRIE_CHILD_MEM; - - // If just reached node - if (childKey === 0) { - // Check if the node has a value - const nodeIndex = childPtr - TRIE_NODE_CHILDREN_IDX; - const valueIndex = tries[trieI][nodeIndex + TRIE_NODE_VALUE_IDX_IDX]; - if (valueIndex !== TRIE_NULL) { - // Print the node's value - if (tail) { - stream.write(separator); - } - tail = true; - callbackFn(stream, key, top, valueIndex); - } - } + stack[top][1] += TRIE_CHILD_MEM; + ++stack[top][2]; // Check if child exists let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX]; - if (childI !== TRIE_NULL) { - // Resolve child if redirect - const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX]; - if (trieI !== childTrieI) { - childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX]; - trieI = childTrieI; + if (childI === TRIE_NULL) { + continue; + } + + // Resolve redirect, if any + const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX]; + if (trieI !== childTrieI) { + childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX]; + trieI = childTrieI; + } + + // Add the child to the stack + key[top] = numChild + UTF8_B0_MIN; + stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0]; + + // Print value, if any + const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX_IDX]; + if (valueIndex !== TRIE_NULL) { + // Print separator if not first value + if (tail) { + stream.write(separator); } - // Add the child to the stack - key[top] = childKey + UTF8_B0_MIN; - stack[++top] = [trieI, 0, childI + TRIE_NODE_CHILDREN_IDX]; + tail = true; + callbackFn(stream, key, top, valueIndex); } } while (top >= 0); } From 9ee4bf6f694f7199fd9828e9ae989b5e4a9df024 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Wed, 22 May 2024 18:34:37 -0400 Subject: [PATCH 10/69] Update best time in README.md --- src/main/nodejs/havelessbemore/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/nodejs/havelessbemore/README.md b/src/main/nodejs/havelessbemore/README.md index 28697c5..f4fc511 100644 --- a/src/main/nodejs/havelessbemore/README.md +++ b/src/main/nodejs/havelessbemore/README.md @@ -14,7 +14,7 @@ ### Results -- Min: 14.8s +- Min: 14.7s - Avg: 15.5s ### Specs: From 360f17e7d4eface63d5b6300c966023c22570f05 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Wed, 22 May 2024 18:55:43 -0400 Subject: [PATCH 11/69] Merge mins and maxes arrays --- src/main/nodejs/havelessbemore/README.md | 2 +- src/main/nodejs/havelessbemore/dist/index.cjs | 47 +++++++++++-------- .../nodejs/havelessbemore/dist/index.cjs.map | 2 +- src/main/nodejs/havelessbemore/dist/index.mjs | 47 +++++++++++-------- .../nodejs/havelessbemore/dist/index.mjs.map | 2 +- src/main/nodejs/havelessbemore/src/main.ts | 30 +++++++----- .../havelessbemore/src/types/workerRequest.ts | 3 +- src/main/nodejs/havelessbemore/src/worker.ts | 17 ++++--- 8 files changed, 85 insertions(+), 65 deletions(-) diff --git a/src/main/nodejs/havelessbemore/README.md b/src/main/nodejs/havelessbemore/README.md index f4fc511..353f0cd 100644 --- a/src/main/nodejs/havelessbemore/README.md +++ b/src/main/nodejs/havelessbemore/README.md @@ -15,7 +15,7 @@ ### Results - Min: 14.7s -- Avg: 15.5s +- Avg: 15.4s ### Specs: diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs b/src/main/nodejs/havelessbemore/dist/index.cjs index cc7eb4d..ef5dbfe 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs +++ b/src/main/nodejs/havelessbemore/dist/index.cjs @@ -224,13 +224,15 @@ async function run$1(filePath, workerPath, maxWorkers, outPath = "") { ); maxWorkers = chunks.length; const numVals = MAX_STATIONS * maxWorkers + 1; - let bpe = Uint32Array.BYTES_PER_ELEMENT; - const counts = new Uint32Array(new SharedArrayBuffer(bpe * numVals)); - bpe = Int16Array.BYTES_PER_ELEMENT; - const maxes = new Int16Array(new SharedArrayBuffer(bpe * numVals)); - const mins = new Int16Array(new SharedArrayBuffer(bpe * numVals)); - bpe = Float64Array.BYTES_PER_ELEMENT; - const sums = new Float64Array(new SharedArrayBuffer(bpe * numVals)); + const counts = new Uint32Array( + new SharedArrayBuffer(Uint32Array.BYTES_PER_ELEMENT * numVals) + ); + const minmaxes = new Int16Array( + new SharedArrayBuffer(2 * Int16Array.BYTES_PER_ELEMENT * numVals) + ); + const sums = new Float64Array( + new SharedArrayBuffer(Float64Array.BYTES_PER_ELEMENT * numVals) + ); const tries = new Array(maxWorkers); const workers = new Array(maxWorkers); for (let i = 0; i < maxWorkers; ++i) { @@ -260,8 +262,7 @@ async function run$1(filePath, workerPath, maxWorkers, outPath = "") { end, filePath, id, - maxes, - mins, + minmaxes, start, sums }); @@ -287,19 +288,22 @@ async function run$1(filePath, workerPath, maxWorkers, outPath = "") { out.end("}\n"); function mergeStations(ai, bi) { counts[ai] += counts[bi]; - maxes[ai] = Math.max(maxes[ai], maxes[bi]); - mins[ai] = Math.min(mins[ai], mins[bi]); sums[ai] += sums[bi]; + ai <<= 1; + bi <<= 1; + minmaxes[ai] = Math.min(minmaxes[ai], minmaxes[bi]); + minmaxes[ai + 1] = Math.max(minmaxes[ai + 1], minmaxes[bi + 1]); } function printStation(stream, name, nameLen, vi) { const avg = Math.round(sums[vi] / counts[vi]); + vi <<= 1; stream.write(name.toString("utf8", 0, nameLen)); stream.write("="); - stream.write((mins[vi] / 10).toFixed(1)); + stream.write((minmaxes[vi] / 10).toFixed(1)); stream.write("/"); stream.write((avg / 10).toFixed(1)); stream.write("/"); - stream.write((maxes[vi] / 10).toFixed(1)); + stream.write((minmaxes[vi + 1] / 10).toFixed(1)); } } @@ -310,8 +314,7 @@ async function run({ start, // Shared memory counts, - maxes, - mins, + minmaxes, sums }) { if (start >= end) { @@ -350,21 +353,25 @@ async function run({ } function newStation(index, temp) { counts[index] = 1; - maxes[index] = temp; - mins[index] = temp; sums[index] = temp; + index <<= 1; + minmaxes[index] = temp; + minmaxes[index + 1] = temp; } function updateStation(index, temp) { ++counts[index]; - maxes[index] = maxes[index] >= temp ? maxes[index] : temp; - mins[index] = mins[index] <= temp ? mins[index] : temp; sums[index] += temp; + index <<= 1; + minmaxes[index] = minmaxes[index] <= temp ? minmaxes[index] : temp; + ++index; + minmaxes[index] = minmaxes[index] >= temp ? minmaxes[index] : temp; } return { id, trie }; } function parseDouble(b, min, max) { if (b[min] === CHAR_MINUS) { - return ++min + 4 > max ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11) : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111); + ++min; + return min + 4 > max ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11) : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111); } return min + 4 > max ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11 : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111; } diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs.map b/src/main/nodejs/havelessbemore/dist/index.cjs.map index 85a173e..1c46b41 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.cjs.map @@ -1 +1 @@ -{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN } from \"./utf8\";\n\n// Trie static properties\n\n/**\n * Represents null / undefined.\n */\nexport const TRIE_NULL = 0;\n\n/**\n * The minimum size a trie.\n */\nexport const MIN_TRIE_SIZE = 524288; // 2 MiB\n\n/**\n * The default growth factor for growing the size of a trie.\n */\nexport const TRIE_GROWTH_FACTOR = 1.618; // ~phi\n\n/**\n * All trie properties are represented by 32 bits (4 bytes).\n */\nexport const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT;\n\n// Trie child pointer properties\n\nexport const TRIE_CHILD_IDX_IDX = 0;\nexport const TRIE_CHILD_IDX_MEM = 1;\n\nexport const TRIE_CHILD_MEM = TRIE_CHILD_IDX_MEM;\n\n// Trie redirect pointer properties\n\nexport const TRIE_RED_ID_IDX = 0;\nexport const TRIE_RED_ID_MEM = 1;\n\nexport const TRIE_RED_VALUE_IDX_IDX = 1;\nexport const TRIE_RED_VALUE_IDX_MEM = 1;\n\nexport const TRIE_RED_MEM = TRIE_RED_ID_MEM + TRIE_RED_VALUE_IDX_MEM;\n\n// Trie node properties\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\nexport const TRIE_NODE_VALUE_IDX_IDX = 1;\nexport const TRIE_NODE_VALUE_IDX_MEM = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_CHILD_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_IDX_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie properties\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_HEADER_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n MIN_TRIE_SIZE,\n TRIE_CHILD_MEM,\n TRIE_CHILD_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_HEADER_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_RED_MEM,\n TRIE_RED_VALUE_IDX_IDX,\n TRIE_RED_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_MEM * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_CHILD_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach and initialize node\n trie[index + TRIE_CHILD_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array {\n const minSize = TRIE_HEADER_MEM;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_CHILD_MEM;\n bi += TRIE_CHILD_MEM;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_CHILD_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_RED_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_RED_MEM);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_RED_MEM;\n // Add new redirect\n tries[at][li + TRIE_RED_ID_IDX] = rt;\n tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_CHILD_MEM;\n bi += TRIE_CHILD_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_CHILD_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_B0_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/utf8Trie\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const numVals = MAX_STATIONS * maxWorkers + 1;\n let bpe = Uint32Array.BYTES_PER_ELEMENT;\n const counts = new Uint32Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Int16Array.BYTES_PER_ELEMENT;\n const maxes = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n const mins = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Float64Array.BYTES_PER_ELEMENT;\n const sums = new Float64Array(new SharedArrayBuffer(bpe * numVals));\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n counts,\n end,\n filePath,\n id,\n maxes,\n mins,\n start,\n sums,\n } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n tries[res.id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 1; i < maxWorkers; ++i) {\n mergeLeft(tries, 0, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(ai: number, bi: number): void {\n counts[ai] += counts[bi];\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n mins[ai] = Math.min(mins[ai], mins[bi]);\n sums[ai] += sums[bi];\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi] / counts[vi]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: WorkerRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n counts[index] = 1;\n maxes[index] = temp;\n mins[index] = temp;\n sums[index] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n ++counts[index];\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n sums[index] += temp;\n }\n\n return { id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n return ++min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [res.trie.buffer]);\n });\n}\n"],"names":["open","at","bt","run","Worker","createWriteStream","createReadStream","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN } from \"./utf8\";\n\n// Trie static properties\n\n/**\n * Represents null / undefined.\n */\nexport const TRIE_NULL = 0;\n\n/**\n * The minimum size a trie.\n */\nexport const MIN_TRIE_SIZE = 524288; // 2 MiB\n\n/**\n * The default growth factor for growing the size of a trie.\n */\nexport const TRIE_GROWTH_FACTOR = 1.618; // ~phi\n\n/**\n * All trie properties are represented by 32 bits (4 bytes).\n */\nexport const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT;\n\n// Trie child pointer properties\n\nexport const TRIE_CHILD_IDX_IDX = 0;\nexport const TRIE_CHILD_IDX_MEM = 1;\n\nexport const TRIE_CHILD_MEM = TRIE_CHILD_IDX_MEM;\n\n// Trie redirect pointer properties\n\nexport const TRIE_RED_ID_IDX = 0;\nexport const TRIE_RED_ID_MEM = 1;\n\nexport const TRIE_RED_VALUE_IDX_IDX = 1;\nexport const TRIE_RED_VALUE_IDX_MEM = 1;\n\nexport const TRIE_RED_MEM = TRIE_RED_ID_MEM + TRIE_RED_VALUE_IDX_MEM;\n\n// Trie node properties\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\nexport const TRIE_NODE_VALUE_IDX_IDX = 1;\nexport const TRIE_NODE_VALUE_IDX_MEM = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_CHILD_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_IDX_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie properties\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_HEADER_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n MIN_TRIE_SIZE,\n TRIE_CHILD_MEM,\n TRIE_CHILD_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_HEADER_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_RED_MEM,\n TRIE_RED_VALUE_IDX_IDX,\n TRIE_RED_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_MEM * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_CHILD_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach and initialize node\n trie[index + TRIE_CHILD_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array {\n const minSize = TRIE_HEADER_MEM;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_CHILD_MEM;\n bi += TRIE_CHILD_MEM;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_CHILD_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_RED_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_RED_MEM);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_RED_MEM;\n // Add new redirect\n tries[at][li + TRIE_RED_ID_IDX] = rt;\n tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_CHILD_MEM;\n bi += TRIE_CHILD_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_CHILD_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_B0_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/utf8Trie\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const numVals = MAX_STATIONS * maxWorkers + 1;\n const counts = new Uint32Array(\n new SharedArrayBuffer(Uint32Array.BYTES_PER_ELEMENT * numVals),\n );\n const minmaxes = new Int16Array(\n new SharedArrayBuffer(2 * Int16Array.BYTES_PER_ELEMENT * numVals),\n );\n const sums = new Float64Array(\n new SharedArrayBuffer(Float64Array.BYTES_PER_ELEMENT * numVals),\n );\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n counts,\n end,\n filePath,\n id,\n minmaxes,\n start,\n sums,\n } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n tries[res.id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 1; i < maxWorkers; ++i) {\n mergeLeft(tries, 0, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(ai: number, bi: number): void {\n counts[ai] += counts[bi];\n sums[ai] += sums[bi];\n ai <<= 1;\n bi <<= 1;\n minmaxes[ai] = Math.min(minmaxes[ai], minmaxes[bi]);\n minmaxes[ai + 1] = Math.max(minmaxes[ai + 1], minmaxes[bi + 1]);\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi] / counts[vi]);\n vi <<= 1;\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((minmaxes[vi] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((minmaxes[vi + 1] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n minmaxes,\n sums,\n}: WorkerRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n counts[index] = 1;\n sums[index] = temp;\n index <<= 1;\n minmaxes[index] = temp;\n minmaxes[index + 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n ++counts[index];\n sums[index] += temp;\n index <<= 1;\n minmaxes[index] = minmaxes[index] <= temp ? minmaxes[index] : temp;\n ++index;\n minmaxes[index] = minmaxes[index] >= temp ? minmaxes[index] : temp;\n }\n\n return { id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [res.trie.buffer]);\n });\n}\n"],"names":["open","at","bt","run","Worker","createWriteStream","createReadStream","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index 5405254..0161306 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -221,13 +221,15 @@ async function run$1(filePath, workerPath, maxWorkers, outPath = "") { ); maxWorkers = chunks.length; const numVals = MAX_STATIONS * maxWorkers + 1; - let bpe = Uint32Array.BYTES_PER_ELEMENT; - const counts = new Uint32Array(new SharedArrayBuffer(bpe * numVals)); - bpe = Int16Array.BYTES_PER_ELEMENT; - const maxes = new Int16Array(new SharedArrayBuffer(bpe * numVals)); - const mins = new Int16Array(new SharedArrayBuffer(bpe * numVals)); - bpe = Float64Array.BYTES_PER_ELEMENT; - const sums = new Float64Array(new SharedArrayBuffer(bpe * numVals)); + const counts = new Uint32Array( + new SharedArrayBuffer(Uint32Array.BYTES_PER_ELEMENT * numVals) + ); + const minmaxes = new Int16Array( + new SharedArrayBuffer(2 * Int16Array.BYTES_PER_ELEMENT * numVals) + ); + const sums = new Float64Array( + new SharedArrayBuffer(Float64Array.BYTES_PER_ELEMENT * numVals) + ); const tries = new Array(maxWorkers); const workers = new Array(maxWorkers); for (let i = 0; i < maxWorkers; ++i) { @@ -257,8 +259,7 @@ async function run$1(filePath, workerPath, maxWorkers, outPath = "") { end, filePath, id, - maxes, - mins, + minmaxes, start, sums }); @@ -284,19 +285,22 @@ async function run$1(filePath, workerPath, maxWorkers, outPath = "") { out.end("}\n"); function mergeStations(ai, bi) { counts[ai] += counts[bi]; - maxes[ai] = Math.max(maxes[ai], maxes[bi]); - mins[ai] = Math.min(mins[ai], mins[bi]); sums[ai] += sums[bi]; + ai <<= 1; + bi <<= 1; + minmaxes[ai] = Math.min(minmaxes[ai], minmaxes[bi]); + minmaxes[ai + 1] = Math.max(minmaxes[ai + 1], minmaxes[bi + 1]); } function printStation(stream, name, nameLen, vi) { const avg = Math.round(sums[vi] / counts[vi]); + vi <<= 1; stream.write(name.toString("utf8", 0, nameLen)); stream.write("="); - stream.write((mins[vi] / 10).toFixed(1)); + stream.write((minmaxes[vi] / 10).toFixed(1)); stream.write("/"); stream.write((avg / 10).toFixed(1)); stream.write("/"); - stream.write((maxes[vi] / 10).toFixed(1)); + stream.write((minmaxes[vi + 1] / 10).toFixed(1)); } } @@ -307,8 +311,7 @@ async function run({ start, // Shared memory counts, - maxes, - mins, + minmaxes, sums }) { if (start >= end) { @@ -347,21 +350,25 @@ async function run({ } function newStation(index, temp) { counts[index] = 1; - maxes[index] = temp; - mins[index] = temp; sums[index] = temp; + index <<= 1; + minmaxes[index] = temp; + minmaxes[index + 1] = temp; } function updateStation(index, temp) { ++counts[index]; - maxes[index] = maxes[index] >= temp ? maxes[index] : temp; - mins[index] = mins[index] <= temp ? mins[index] : temp; sums[index] += temp; + index <<= 1; + minmaxes[index] = minmaxes[index] <= temp ? minmaxes[index] : temp; + ++index; + minmaxes[index] = minmaxes[index] >= temp ? minmaxes[index] : temp; } return { id, trie }; } function parseDouble(b, min, max) { if (b[min] === CHAR_MINUS) { - return ++min + 4 > max ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11) : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111); + ++min; + return min + 4 > max ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11) : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111); } return min + 4 > max ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11 : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111; } diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index e2fc872..de43f8c 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1 +1 @@ -{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN } from \"./utf8\";\n\n// Trie static properties\n\n/**\n * Represents null / undefined.\n */\nexport const TRIE_NULL = 0;\n\n/**\n * The minimum size a trie.\n */\nexport const MIN_TRIE_SIZE = 524288; // 2 MiB\n\n/**\n * The default growth factor for growing the size of a trie.\n */\nexport const TRIE_GROWTH_FACTOR = 1.618; // ~phi\n\n/**\n * All trie properties are represented by 32 bits (4 bytes).\n */\nexport const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT;\n\n// Trie child pointer properties\n\nexport const TRIE_CHILD_IDX_IDX = 0;\nexport const TRIE_CHILD_IDX_MEM = 1;\n\nexport const TRIE_CHILD_MEM = TRIE_CHILD_IDX_MEM;\n\n// Trie redirect pointer properties\n\nexport const TRIE_RED_ID_IDX = 0;\nexport const TRIE_RED_ID_MEM = 1;\n\nexport const TRIE_RED_VALUE_IDX_IDX = 1;\nexport const TRIE_RED_VALUE_IDX_MEM = 1;\n\nexport const TRIE_RED_MEM = TRIE_RED_ID_MEM + TRIE_RED_VALUE_IDX_MEM;\n\n// Trie node properties\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\nexport const TRIE_NODE_VALUE_IDX_IDX = 1;\nexport const TRIE_NODE_VALUE_IDX_MEM = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_CHILD_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_IDX_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie properties\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_HEADER_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n MIN_TRIE_SIZE,\n TRIE_CHILD_MEM,\n TRIE_CHILD_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_HEADER_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_RED_MEM,\n TRIE_RED_VALUE_IDX_IDX,\n TRIE_RED_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_MEM * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_CHILD_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach and initialize node\n trie[index + TRIE_CHILD_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array {\n const minSize = TRIE_HEADER_MEM;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_CHILD_MEM;\n bi += TRIE_CHILD_MEM;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_CHILD_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_RED_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_RED_MEM);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_RED_MEM;\n // Add new redirect\n tries[at][li + TRIE_RED_ID_IDX] = rt;\n tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_CHILD_MEM;\n bi += TRIE_CHILD_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_CHILD_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_B0_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/utf8Trie\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const numVals = MAX_STATIONS * maxWorkers + 1;\n let bpe = Uint32Array.BYTES_PER_ELEMENT;\n const counts = new Uint32Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Int16Array.BYTES_PER_ELEMENT;\n const maxes = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n const mins = new Int16Array(new SharedArrayBuffer(bpe * numVals));\n bpe = Float64Array.BYTES_PER_ELEMENT;\n const sums = new Float64Array(new SharedArrayBuffer(bpe * numVals));\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n counts,\n end,\n filePath,\n id,\n maxes,\n mins,\n start,\n sums,\n } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n tries[res.id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 1; i < maxWorkers; ++i) {\n mergeLeft(tries, 0, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(ai: number, bi: number): void {\n counts[ai] += counts[bi];\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n mins[ai] = Math.min(mins[ai], mins[bi]);\n sums[ai] += sums[bi];\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi] / counts[vi]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: WorkerRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n counts[index] = 1;\n maxes[index] = temp;\n mins[index] = temp;\n sums[index] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n ++counts[index];\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n sums[index] += temp;\n }\n\n return { id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n return ++min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [res.trie.buffer]);\n });\n}\n"],"names":["at","bt","run","runMain","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN } from \"./utf8\";\n\n// Trie static properties\n\n/**\n * Represents null / undefined.\n */\nexport const TRIE_NULL = 0;\n\n/**\n * The minimum size a trie.\n */\nexport const MIN_TRIE_SIZE = 524288; // 2 MiB\n\n/**\n * The default growth factor for growing the size of a trie.\n */\nexport const TRIE_GROWTH_FACTOR = 1.618; // ~phi\n\n/**\n * All trie properties are represented by 32 bits (4 bytes).\n */\nexport const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT;\n\n// Trie child pointer properties\n\nexport const TRIE_CHILD_IDX_IDX = 0;\nexport const TRIE_CHILD_IDX_MEM = 1;\n\nexport const TRIE_CHILD_MEM = TRIE_CHILD_IDX_MEM;\n\n// Trie redirect pointer properties\n\nexport const TRIE_RED_ID_IDX = 0;\nexport const TRIE_RED_ID_MEM = 1;\n\nexport const TRIE_RED_VALUE_IDX_IDX = 1;\nexport const TRIE_RED_VALUE_IDX_MEM = 1;\n\nexport const TRIE_RED_MEM = TRIE_RED_ID_MEM + TRIE_RED_VALUE_IDX_MEM;\n\n// Trie node properties\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\nexport const TRIE_NODE_VALUE_IDX_IDX = 1;\nexport const TRIE_NODE_VALUE_IDX_MEM = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_CHILD_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_IDX_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie properties\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_HEADER_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n MIN_TRIE_SIZE,\n TRIE_CHILD_MEM,\n TRIE_CHILD_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_HEADER_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_RED_MEM,\n TRIE_RED_VALUE_IDX_IDX,\n TRIE_RED_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_MEM * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_CHILD_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach and initialize node\n trie[index + TRIE_CHILD_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array {\n const minSize = TRIE_HEADER_MEM;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_CHILD_MEM;\n bi += TRIE_CHILD_MEM;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_CHILD_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_RED_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_RED_MEM);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_RED_MEM;\n // Add new redirect\n tries[at][li + TRIE_RED_ID_IDX] = rt;\n tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_CHILD_MEM;\n bi += TRIE_CHILD_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_CHILD_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_B0_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/utf8Trie\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const numVals = MAX_STATIONS * maxWorkers + 1;\n const counts = new Uint32Array(\n new SharedArrayBuffer(Uint32Array.BYTES_PER_ELEMENT * numVals),\n );\n const minmaxes = new Int16Array(\n new SharedArrayBuffer(2 * Int16Array.BYTES_PER_ELEMENT * numVals),\n );\n const sums = new Float64Array(\n new SharedArrayBuffer(Float64Array.BYTES_PER_ELEMENT * numVals),\n );\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n counts,\n end,\n filePath,\n id,\n minmaxes,\n start,\n sums,\n } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n tries[res.id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 1; i < maxWorkers; ++i) {\n mergeLeft(tries, 0, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(ai: number, bi: number): void {\n counts[ai] += counts[bi];\n sums[ai] += sums[bi];\n ai <<= 1;\n bi <<= 1;\n minmaxes[ai] = Math.min(minmaxes[ai], minmaxes[bi]);\n minmaxes[ai + 1] = Math.max(minmaxes[ai + 1], minmaxes[bi + 1]);\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi] / counts[vi]);\n vi <<= 1;\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((minmaxes[vi] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((minmaxes[vi + 1] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n minmaxes,\n sums,\n}: WorkerRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n counts[index] = 1;\n sums[index] = temp;\n index <<= 1;\n minmaxes[index] = temp;\n minmaxes[index + 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n ++counts[index];\n sums[index] += temp;\n index <<= 1;\n minmaxes[index] = minmaxes[index] <= temp ? minmaxes[index] : temp;\n ++index;\n minmaxes[index] = minmaxes[index] >= temp ? minmaxes[index] : temp;\n }\n\n return { id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [res.trie.buffer]);\n });\n}\n"],"names":["at","bt","run","runMain","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/src/main.ts b/src/main/nodejs/havelessbemore/src/main.ts index 9715102..f7f544d 100644 --- a/src/main/nodejs/havelessbemore/src/main.ts +++ b/src/main/nodejs/havelessbemore/src/main.ts @@ -36,13 +36,15 @@ export async function run( // Initialize data const numVals = MAX_STATIONS * maxWorkers + 1; - let bpe = Uint32Array.BYTES_PER_ELEMENT; - const counts = new Uint32Array(new SharedArrayBuffer(bpe * numVals)); - bpe = Int16Array.BYTES_PER_ELEMENT; - const maxes = new Int16Array(new SharedArrayBuffer(bpe * numVals)); - const mins = new Int16Array(new SharedArrayBuffer(bpe * numVals)); - bpe = Float64Array.BYTES_PER_ELEMENT; - const sums = new Float64Array(new SharedArrayBuffer(bpe * numVals)); + const counts = new Uint32Array( + new SharedArrayBuffer(Uint32Array.BYTES_PER_ELEMENT * numVals), + ); + const minmaxes = new Int16Array( + new SharedArrayBuffer(2 * Int16Array.BYTES_PER_ELEMENT * numVals), + ); + const sums = new Float64Array( + new SharedArrayBuffer(Float64Array.BYTES_PER_ELEMENT * numVals), + ); const tries: Int32Array[] = new Array(maxWorkers); // Create workers @@ -76,8 +78,7 @@ export async function run( end, filePath, id, - maxes, - mins, + minmaxes, start, sums, } as WorkerRequest); @@ -112,9 +113,11 @@ export async function run( function mergeStations(ai: number, bi: number): void { counts[ai] += counts[bi]; - maxes[ai] = Math.max(maxes[ai], maxes[bi]); - mins[ai] = Math.min(mins[ai], mins[bi]); sums[ai] += sums[bi]; + ai <<= 1; + bi <<= 1; + minmaxes[ai] = Math.min(minmaxes[ai], minmaxes[bi]); + minmaxes[ai + 1] = Math.max(minmaxes[ai + 1], minmaxes[bi + 1]); } function printStation( @@ -124,12 +127,13 @@ export async function run( vi: number, ): void { const avg = Math.round(sums[vi] / counts[vi]); + vi <<= 1; stream.write(name.toString("utf8", 0, nameLen)); stream.write("="); - stream.write((mins[vi] / 10).toFixed(1)); + stream.write((minmaxes[vi] / 10).toFixed(1)); stream.write("/"); stream.write((avg / 10).toFixed(1)); stream.write("/"); - stream.write((maxes[vi] / 10).toFixed(1)); + stream.write((minmaxes[vi + 1] / 10).toFixed(1)); } } diff --git a/src/main/nodejs/havelessbemore/src/types/workerRequest.ts b/src/main/nodejs/havelessbemore/src/types/workerRequest.ts index 88909f9..33485fb 100644 --- a/src/main/nodejs/havelessbemore/src/types/workerRequest.ts +++ b/src/main/nodejs/havelessbemore/src/types/workerRequest.ts @@ -5,7 +5,6 @@ export interface WorkerRequest { start: number; // Shared memory counts: Uint32Array; - maxes: Int16Array; - mins: Int16Array; + minmaxes: Int16Array; sums: Float64Array; } diff --git a/src/main/nodejs/havelessbemore/src/worker.ts b/src/main/nodejs/havelessbemore/src/worker.ts index dca5ce4..66645da 100644 --- a/src/main/nodejs/havelessbemore/src/worker.ts +++ b/src/main/nodejs/havelessbemore/src/worker.ts @@ -19,8 +19,7 @@ export async function run({ start, // Shared memory counts, - maxes, - mins, + minmaxes, sums, }: WorkerRequest): Promise { // Check chunk size @@ -75,16 +74,19 @@ export async function run({ function newStation(index: number, temp: number): void { counts[index] = 1; - maxes[index] = temp; - mins[index] = temp; sums[index] = temp; + index <<= 1; + minmaxes[index] = temp; + minmaxes[index + 1] = temp; } function updateStation(index: number, temp: number): void { ++counts[index]; - maxes[index] = maxes[index] >= temp ? maxes[index] : temp; - mins[index] = mins[index] <= temp ? mins[index] : temp; sums[index] += temp; + index <<= 1; + minmaxes[index] = minmaxes[index] <= temp ? minmaxes[index] : temp; + ++index; + minmaxes[index] = minmaxes[index] >= temp ? minmaxes[index] : temp; } return { id, trie }; @@ -92,7 +94,8 @@ export async function run({ export function parseDouble(b: Buffer, min: number, max: number): number { if (b[min] === CHAR_MINUS) { - return ++min + 4 > max + ++min; + return min + 4 > max ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11) : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111); } From a483f80436de282cec464d41b6ea31d05fc291e5 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Wed, 22 May 2024 20:10:21 -0400 Subject: [PATCH 12/69] Merge values in memory --- src/main/nodejs/havelessbemore/README.md | 2 +- src/main/nodejs/havelessbemore/dist/index.cjs | 65 ++++++++++--------- .../nodejs/havelessbemore/dist/index.cjs.map | 2 +- src/main/nodejs/havelessbemore/dist/index.mjs | 65 ++++++++++--------- .../nodejs/havelessbemore/dist/index.mjs.map | 2 +- src/main/nodejs/havelessbemore/src/main.ts | 46 +++++++------ .../havelessbemore/src/types/workerRequest.ts | 3 +- src/main/nodejs/havelessbemore/src/worker.ts | 23 ++++--- 8 files changed, 110 insertions(+), 98 deletions(-) diff --git a/src/main/nodejs/havelessbemore/README.md b/src/main/nodejs/havelessbemore/README.md index 353f0cd..040bb77 100644 --- a/src/main/nodejs/havelessbemore/README.md +++ b/src/main/nodejs/havelessbemore/README.md @@ -14,7 +14,7 @@ ### Results -- Min: 14.7s +- Min: 14.5s - Avg: 15.4s ### Specs: diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs b/src/main/nodejs/havelessbemore/dist/index.cjs index ef5dbfe..a63332c 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs +++ b/src/main/nodejs/havelessbemore/dist/index.cjs @@ -223,16 +223,20 @@ async function run$1(filePath, workerPath, maxWorkers, outPath = "") { CHUNK_SIZE_MIN ); maxWorkers = chunks.length; - const numVals = MAX_STATIONS * maxWorkers + 1; - const counts = new Uint32Array( - new SharedArrayBuffer(Uint32Array.BYTES_PER_ELEMENT * numVals) + const BPE = ( + // Count + Uint32Array.BYTES_PER_ELEMENT + // Max + Int16Array.BYTES_PER_ELEMENT + // Min + Int16Array.BYTES_PER_ELEMENT + // Sum + Float64Array.BYTES_PER_ELEMENT ); - const minmaxes = new Int16Array( - new SharedArrayBuffer(2 * Int16Array.BYTES_PER_ELEMENT * numVals) - ); - const sums = new Float64Array( - new SharedArrayBuffer(Float64Array.BYTES_PER_ELEMENT * numVals) + const valuesBuffer = new SharedArrayBuffer( + BPE * (MAX_STATIONS * maxWorkers + 1) ); + const mins = new Int16Array(valuesBuffer); + const maxes = new Int16Array(valuesBuffer, Int16Array.BYTES_PER_ELEMENT); + const counts = new Uint32Array(valuesBuffer, Uint32Array.BYTES_PER_ELEMENT); + const sums = new Float64Array(valuesBuffer, Float64Array.BYTES_PER_ELEMENT); const tries = new Array(maxWorkers); const workers = new Array(maxWorkers); for (let i = 0; i < maxWorkers; ++i) { @@ -262,7 +266,8 @@ async function run$1(filePath, workerPath, maxWorkers, outPath = "") { end, filePath, id, - minmaxes, + maxes, + mins, start, sums }); @@ -287,23 +292,22 @@ async function run$1(filePath, workerPath, maxWorkers, outPath = "") { print(tries, buffer, 0, out, ", ", printStation); out.end("}\n"); function mergeStations(ai, bi) { - counts[ai] += counts[bi]; - sums[ai] += sums[bi]; - ai <<= 1; - bi <<= 1; - minmaxes[ai] = Math.min(minmaxes[ai], minmaxes[bi]); - minmaxes[ai + 1] = Math.max(minmaxes[ai + 1], minmaxes[bi + 1]); + ai <<= 3; + bi <<= 3; + mins[ai] = Math.min(mins[ai], mins[bi]); + maxes[ai] = Math.max(maxes[ai], maxes[bi]); + counts[ai >> 1] += counts[bi >> 1]; + sums[ai >> 2] += sums[bi >> 2]; } function printStation(stream, name, nameLen, vi) { - const avg = Math.round(sums[vi] / counts[vi]); - vi <<= 1; + const avg = Math.round(sums[vi << 1] / counts[vi << 2]); stream.write(name.toString("utf8", 0, nameLen)); stream.write("="); - stream.write((minmaxes[vi] / 10).toFixed(1)); + stream.write((mins[vi << 3] / 10).toFixed(1)); stream.write("/"); stream.write((avg / 10).toFixed(1)); stream.write("/"); - stream.write((minmaxes[vi + 1] / 10).toFixed(1)); + stream.write((maxes[vi << 3] / 10).toFixed(1)); } } @@ -314,7 +318,8 @@ async function run({ start, // Shared memory counts, - minmaxes, + maxes, + mins, sums }) { if (start >= end) { @@ -352,19 +357,17 @@ async function run({ } } function newStation(index, temp) { - counts[index] = 1; - sums[index] = temp; - index <<= 1; - minmaxes[index] = temp; - minmaxes[index + 1] = temp; + mins[index << 3] = temp; + maxes[index << 3] = temp; + counts[index << 2] = 1; + sums[index << 1] = temp; } function updateStation(index, temp) { - ++counts[index]; - sums[index] += temp; - index <<= 1; - minmaxes[index] = minmaxes[index] <= temp ? minmaxes[index] : temp; - ++index; - minmaxes[index] = minmaxes[index] >= temp ? minmaxes[index] : temp; + index <<= 3; + mins[index] = mins[index] <= temp ? mins[index] : temp; + maxes[index] = maxes[index] >= temp ? maxes[index] : temp; + ++counts[index >> 1]; + sums[index >> 2] += temp; } return { id, trie }; } diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs.map b/src/main/nodejs/havelessbemore/dist/index.cjs.map index 1c46b41..95cc035 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.cjs.map @@ -1 +1 @@ -{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN } from \"./utf8\";\n\n// Trie static properties\n\n/**\n * Represents null / undefined.\n */\nexport const TRIE_NULL = 0;\n\n/**\n * The minimum size a trie.\n */\nexport const MIN_TRIE_SIZE = 524288; // 2 MiB\n\n/**\n * The default growth factor for growing the size of a trie.\n */\nexport const TRIE_GROWTH_FACTOR = 1.618; // ~phi\n\n/**\n * All trie properties are represented by 32 bits (4 bytes).\n */\nexport const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT;\n\n// Trie child pointer properties\n\nexport const TRIE_CHILD_IDX_IDX = 0;\nexport const TRIE_CHILD_IDX_MEM = 1;\n\nexport const TRIE_CHILD_MEM = TRIE_CHILD_IDX_MEM;\n\n// Trie redirect pointer properties\n\nexport const TRIE_RED_ID_IDX = 0;\nexport const TRIE_RED_ID_MEM = 1;\n\nexport const TRIE_RED_VALUE_IDX_IDX = 1;\nexport const TRIE_RED_VALUE_IDX_MEM = 1;\n\nexport const TRIE_RED_MEM = TRIE_RED_ID_MEM + TRIE_RED_VALUE_IDX_MEM;\n\n// Trie node properties\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\nexport const TRIE_NODE_VALUE_IDX_IDX = 1;\nexport const TRIE_NODE_VALUE_IDX_MEM = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_CHILD_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_IDX_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie properties\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_HEADER_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n MIN_TRIE_SIZE,\n TRIE_CHILD_MEM,\n TRIE_CHILD_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_HEADER_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_RED_MEM,\n TRIE_RED_VALUE_IDX_IDX,\n TRIE_RED_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_MEM * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_CHILD_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach and initialize node\n trie[index + TRIE_CHILD_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array {\n const minSize = TRIE_HEADER_MEM;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_CHILD_MEM;\n bi += TRIE_CHILD_MEM;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_CHILD_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_RED_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_RED_MEM);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_RED_MEM;\n // Add new redirect\n tries[at][li + TRIE_RED_ID_IDX] = rt;\n tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_CHILD_MEM;\n bi += TRIE_CHILD_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_CHILD_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_B0_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/utf8Trie\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const numVals = MAX_STATIONS * maxWorkers + 1;\n const counts = new Uint32Array(\n new SharedArrayBuffer(Uint32Array.BYTES_PER_ELEMENT * numVals),\n );\n const minmaxes = new Int16Array(\n new SharedArrayBuffer(2 * Int16Array.BYTES_PER_ELEMENT * numVals),\n );\n const sums = new Float64Array(\n new SharedArrayBuffer(Float64Array.BYTES_PER_ELEMENT * numVals),\n );\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n counts,\n end,\n filePath,\n id,\n minmaxes,\n start,\n sums,\n } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n tries[res.id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 1; i < maxWorkers; ++i) {\n mergeLeft(tries, 0, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(ai: number, bi: number): void {\n counts[ai] += counts[bi];\n sums[ai] += sums[bi];\n ai <<= 1;\n bi <<= 1;\n minmaxes[ai] = Math.min(minmaxes[ai], minmaxes[bi]);\n minmaxes[ai + 1] = Math.max(minmaxes[ai + 1], minmaxes[bi + 1]);\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi] / counts[vi]);\n vi <<= 1;\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((minmaxes[vi] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((minmaxes[vi + 1] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n minmaxes,\n sums,\n}: WorkerRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n counts[index] = 1;\n sums[index] = temp;\n index <<= 1;\n minmaxes[index] = temp;\n minmaxes[index + 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n ++counts[index];\n sums[index] += temp;\n index <<= 1;\n minmaxes[index] = minmaxes[index] <= temp ? minmaxes[index] : temp;\n ++index;\n minmaxes[index] = minmaxes[index] >= temp ? minmaxes[index] : temp;\n }\n\n return { id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [res.trie.buffer]);\n });\n}\n"],"names":["open","at","bt","run","Worker","createWriteStream","createReadStream","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN } from \"./utf8\";\n\n// Trie static properties\n\n/**\n * Represents null / undefined.\n */\nexport const TRIE_NULL = 0;\n\n/**\n * The minimum size a trie.\n */\nexport const MIN_TRIE_SIZE = 524288; // 2 MiB\n\n/**\n * The default growth factor for growing the size of a trie.\n */\nexport const TRIE_GROWTH_FACTOR = 1.618; // ~phi\n\n/**\n * All trie properties are represented by 32 bits (4 bytes).\n */\nexport const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT;\n\n// Trie child pointer properties\n\nexport const TRIE_CHILD_IDX_IDX = 0;\nexport const TRIE_CHILD_IDX_MEM = 1;\n\nexport const TRIE_CHILD_MEM = TRIE_CHILD_IDX_MEM;\n\n// Trie redirect pointer properties\n\nexport const TRIE_RED_ID_IDX = 0;\nexport const TRIE_RED_ID_MEM = 1;\n\nexport const TRIE_RED_VALUE_IDX_IDX = 1;\nexport const TRIE_RED_VALUE_IDX_MEM = 1;\n\nexport const TRIE_RED_MEM = TRIE_RED_ID_MEM + TRIE_RED_VALUE_IDX_MEM;\n\n// Trie node properties\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\nexport const TRIE_NODE_VALUE_IDX_IDX = 1;\nexport const TRIE_NODE_VALUE_IDX_MEM = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_CHILD_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_IDX_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie properties\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_HEADER_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n MIN_TRIE_SIZE,\n TRIE_CHILD_MEM,\n TRIE_CHILD_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_HEADER_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_RED_MEM,\n TRIE_RED_VALUE_IDX_IDX,\n TRIE_RED_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_MEM * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_CHILD_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach and initialize node\n trie[index + TRIE_CHILD_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array {\n const minSize = TRIE_HEADER_MEM;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_CHILD_MEM;\n bi += TRIE_CHILD_MEM;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_CHILD_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_RED_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_RED_MEM);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_RED_MEM;\n // Add new redirect\n tries[at][li + TRIE_RED_ID_IDX] = rt;\n tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_CHILD_MEM;\n bi += TRIE_CHILD_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_CHILD_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_B0_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/utf8Trie\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const BPE =\n // Count\n Uint32Array.BYTES_PER_ELEMENT +\n // Max\n Int16Array.BYTES_PER_ELEMENT +\n // Min\n Int16Array.BYTES_PER_ELEMENT +\n // Sum\n Float64Array.BYTES_PER_ELEMENT;\n const valuesBuffer = new SharedArrayBuffer(\n BPE * (MAX_STATIONS * maxWorkers + 1),\n );\n const mins = new Int16Array(valuesBuffer);\n const maxes = new Int16Array(valuesBuffer, Int16Array.BYTES_PER_ELEMENT);\n const counts = new Uint32Array(valuesBuffer, Uint32Array.BYTES_PER_ELEMENT);\n const sums = new Float64Array(valuesBuffer, Float64Array.BYTES_PER_ELEMENT);\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n counts,\n end,\n filePath,\n id,\n maxes,\n mins,\n start,\n sums,\n } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n tries[res.id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 1; i < maxWorkers; ++i) {\n mergeLeft(tries, 0, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: WorkerRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [res.trie.buffer]);\n });\n}\n"],"names":["open","at","bt","run","Worker","createWriteStream","createReadStream","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index 0161306..9c2cb03 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -220,16 +220,20 @@ async function run$1(filePath, workerPath, maxWorkers, outPath = "") { CHUNK_SIZE_MIN ); maxWorkers = chunks.length; - const numVals = MAX_STATIONS * maxWorkers + 1; - const counts = new Uint32Array( - new SharedArrayBuffer(Uint32Array.BYTES_PER_ELEMENT * numVals) + const BPE = ( + // Count + Uint32Array.BYTES_PER_ELEMENT + // Max + Int16Array.BYTES_PER_ELEMENT + // Min + Int16Array.BYTES_PER_ELEMENT + // Sum + Float64Array.BYTES_PER_ELEMENT ); - const minmaxes = new Int16Array( - new SharedArrayBuffer(2 * Int16Array.BYTES_PER_ELEMENT * numVals) - ); - const sums = new Float64Array( - new SharedArrayBuffer(Float64Array.BYTES_PER_ELEMENT * numVals) + const valuesBuffer = new SharedArrayBuffer( + BPE * (MAX_STATIONS * maxWorkers + 1) ); + const mins = new Int16Array(valuesBuffer); + const maxes = new Int16Array(valuesBuffer, Int16Array.BYTES_PER_ELEMENT); + const counts = new Uint32Array(valuesBuffer, Uint32Array.BYTES_PER_ELEMENT); + const sums = new Float64Array(valuesBuffer, Float64Array.BYTES_PER_ELEMENT); const tries = new Array(maxWorkers); const workers = new Array(maxWorkers); for (let i = 0; i < maxWorkers; ++i) { @@ -259,7 +263,8 @@ async function run$1(filePath, workerPath, maxWorkers, outPath = "") { end, filePath, id, - minmaxes, + maxes, + mins, start, sums }); @@ -284,23 +289,22 @@ async function run$1(filePath, workerPath, maxWorkers, outPath = "") { print(tries, buffer, 0, out, ", ", printStation); out.end("}\n"); function mergeStations(ai, bi) { - counts[ai] += counts[bi]; - sums[ai] += sums[bi]; - ai <<= 1; - bi <<= 1; - minmaxes[ai] = Math.min(minmaxes[ai], minmaxes[bi]); - minmaxes[ai + 1] = Math.max(minmaxes[ai + 1], minmaxes[bi + 1]); + ai <<= 3; + bi <<= 3; + mins[ai] = Math.min(mins[ai], mins[bi]); + maxes[ai] = Math.max(maxes[ai], maxes[bi]); + counts[ai >> 1] += counts[bi >> 1]; + sums[ai >> 2] += sums[bi >> 2]; } function printStation(stream, name, nameLen, vi) { - const avg = Math.round(sums[vi] / counts[vi]); - vi <<= 1; + const avg = Math.round(sums[vi << 1] / counts[vi << 2]); stream.write(name.toString("utf8", 0, nameLen)); stream.write("="); - stream.write((minmaxes[vi] / 10).toFixed(1)); + stream.write((mins[vi << 3] / 10).toFixed(1)); stream.write("/"); stream.write((avg / 10).toFixed(1)); stream.write("/"); - stream.write((minmaxes[vi + 1] / 10).toFixed(1)); + stream.write((maxes[vi << 3] / 10).toFixed(1)); } } @@ -311,7 +315,8 @@ async function run({ start, // Shared memory counts, - minmaxes, + maxes, + mins, sums }) { if (start >= end) { @@ -349,19 +354,17 @@ async function run({ } } function newStation(index, temp) { - counts[index] = 1; - sums[index] = temp; - index <<= 1; - minmaxes[index] = temp; - minmaxes[index + 1] = temp; + mins[index << 3] = temp; + maxes[index << 3] = temp; + counts[index << 2] = 1; + sums[index << 1] = temp; } function updateStation(index, temp) { - ++counts[index]; - sums[index] += temp; - index <<= 1; - minmaxes[index] = minmaxes[index] <= temp ? minmaxes[index] : temp; - ++index; - minmaxes[index] = minmaxes[index] >= temp ? minmaxes[index] : temp; + index <<= 3; + mins[index] = mins[index] <= temp ? mins[index] : temp; + maxes[index] = maxes[index] >= temp ? maxes[index] : temp; + ++counts[index >> 1]; + sums[index >> 2] += temp; } return { id, trie }; } diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index de43f8c..4d27353 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1 +1 @@ -{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN } from \"./utf8\";\n\n// Trie static properties\n\n/**\n * Represents null / undefined.\n */\nexport const TRIE_NULL = 0;\n\n/**\n * The minimum size a trie.\n */\nexport const MIN_TRIE_SIZE = 524288; // 2 MiB\n\n/**\n * The default growth factor for growing the size of a trie.\n */\nexport const TRIE_GROWTH_FACTOR = 1.618; // ~phi\n\n/**\n * All trie properties are represented by 32 bits (4 bytes).\n */\nexport const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT;\n\n// Trie child pointer properties\n\nexport const TRIE_CHILD_IDX_IDX = 0;\nexport const TRIE_CHILD_IDX_MEM = 1;\n\nexport const TRIE_CHILD_MEM = TRIE_CHILD_IDX_MEM;\n\n// Trie redirect pointer properties\n\nexport const TRIE_RED_ID_IDX = 0;\nexport const TRIE_RED_ID_MEM = 1;\n\nexport const TRIE_RED_VALUE_IDX_IDX = 1;\nexport const TRIE_RED_VALUE_IDX_MEM = 1;\n\nexport const TRIE_RED_MEM = TRIE_RED_ID_MEM + TRIE_RED_VALUE_IDX_MEM;\n\n// Trie node properties\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\nexport const TRIE_NODE_VALUE_IDX_IDX = 1;\nexport const TRIE_NODE_VALUE_IDX_MEM = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_CHILD_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_IDX_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie properties\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_HEADER_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n MIN_TRIE_SIZE,\n TRIE_CHILD_MEM,\n TRIE_CHILD_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_HEADER_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_RED_MEM,\n TRIE_RED_VALUE_IDX_IDX,\n TRIE_RED_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_MEM * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_CHILD_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach and initialize node\n trie[index + TRIE_CHILD_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array {\n const minSize = TRIE_HEADER_MEM;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_CHILD_MEM;\n bi += TRIE_CHILD_MEM;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_CHILD_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_RED_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_RED_MEM);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_RED_MEM;\n // Add new redirect\n tries[at][li + TRIE_RED_ID_IDX] = rt;\n tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_CHILD_MEM;\n bi += TRIE_CHILD_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_CHILD_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_B0_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/utf8Trie\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const numVals = MAX_STATIONS * maxWorkers + 1;\n const counts = new Uint32Array(\n new SharedArrayBuffer(Uint32Array.BYTES_PER_ELEMENT * numVals),\n );\n const minmaxes = new Int16Array(\n new SharedArrayBuffer(2 * Int16Array.BYTES_PER_ELEMENT * numVals),\n );\n const sums = new Float64Array(\n new SharedArrayBuffer(Float64Array.BYTES_PER_ELEMENT * numVals),\n );\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n counts,\n end,\n filePath,\n id,\n minmaxes,\n start,\n sums,\n } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n tries[res.id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 1; i < maxWorkers; ++i) {\n mergeLeft(tries, 0, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(ai: number, bi: number): void {\n counts[ai] += counts[bi];\n sums[ai] += sums[bi];\n ai <<= 1;\n bi <<= 1;\n minmaxes[ai] = Math.min(minmaxes[ai], minmaxes[bi]);\n minmaxes[ai + 1] = Math.max(minmaxes[ai + 1], minmaxes[bi + 1]);\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi] / counts[vi]);\n vi <<= 1;\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((minmaxes[vi] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((minmaxes[vi + 1] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n minmaxes,\n sums,\n}: WorkerRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n counts[index] = 1;\n sums[index] = temp;\n index <<= 1;\n minmaxes[index] = temp;\n minmaxes[index + 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n ++counts[index];\n sums[index] += temp;\n index <<= 1;\n minmaxes[index] = minmaxes[index] <= temp ? minmaxes[index] : temp;\n ++index;\n minmaxes[index] = minmaxes[index] >= temp ? minmaxes[index] : temp;\n }\n\n return { id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [res.trie.buffer]);\n });\n}\n"],"names":["at","bt","run","runMain","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN } from \"./utf8\";\n\n// Trie static properties\n\n/**\n * Represents null / undefined.\n */\nexport const TRIE_NULL = 0;\n\n/**\n * The minimum size a trie.\n */\nexport const MIN_TRIE_SIZE = 524288; // 2 MiB\n\n/**\n * The default growth factor for growing the size of a trie.\n */\nexport const TRIE_GROWTH_FACTOR = 1.618; // ~phi\n\n/**\n * All trie properties are represented by 32 bits (4 bytes).\n */\nexport const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT;\n\n// Trie child pointer properties\n\nexport const TRIE_CHILD_IDX_IDX = 0;\nexport const TRIE_CHILD_IDX_MEM = 1;\n\nexport const TRIE_CHILD_MEM = TRIE_CHILD_IDX_MEM;\n\n// Trie redirect pointer properties\n\nexport const TRIE_RED_ID_IDX = 0;\nexport const TRIE_RED_ID_MEM = 1;\n\nexport const TRIE_RED_VALUE_IDX_IDX = 1;\nexport const TRIE_RED_VALUE_IDX_MEM = 1;\n\nexport const TRIE_RED_MEM = TRIE_RED_ID_MEM + TRIE_RED_VALUE_IDX_MEM;\n\n// Trie node properties\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\nexport const TRIE_NODE_VALUE_IDX_IDX = 1;\nexport const TRIE_NODE_VALUE_IDX_MEM = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_CHILD_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_IDX_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie properties\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_HEADER_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n MIN_TRIE_SIZE,\n TRIE_CHILD_MEM,\n TRIE_CHILD_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_HEADER_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_RED_MEM,\n TRIE_RED_VALUE_IDX_IDX,\n TRIE_RED_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_MEM * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_CHILD_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach and initialize node\n trie[index + TRIE_CHILD_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array {\n const minSize = TRIE_HEADER_MEM;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_CHILD_MEM;\n bi += TRIE_CHILD_MEM;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_CHILD_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_RED_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_RED_MEM);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_RED_MEM;\n // Add new redirect\n tries[at][li + TRIE_RED_ID_IDX] = rt;\n tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_CHILD_MEM;\n bi += TRIE_CHILD_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_CHILD_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_B0_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/utf8Trie\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const BPE =\n // Count\n Uint32Array.BYTES_PER_ELEMENT +\n // Max\n Int16Array.BYTES_PER_ELEMENT +\n // Min\n Int16Array.BYTES_PER_ELEMENT +\n // Sum\n Float64Array.BYTES_PER_ELEMENT;\n const valuesBuffer = new SharedArrayBuffer(\n BPE * (MAX_STATIONS * maxWorkers + 1),\n );\n const mins = new Int16Array(valuesBuffer);\n const maxes = new Int16Array(valuesBuffer, Int16Array.BYTES_PER_ELEMENT);\n const counts = new Uint32Array(valuesBuffer, Uint32Array.BYTES_PER_ELEMENT);\n const sums = new Float64Array(valuesBuffer, Float64Array.BYTES_PER_ELEMENT);\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n counts,\n end,\n filePath,\n id,\n maxes,\n mins,\n start,\n sums,\n } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n tries[res.id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 1; i < maxWorkers; ++i) {\n mergeLeft(tries, 0, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: WorkerRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [res.trie.buffer]);\n });\n}\n"],"names":["at","bt","run","runMain","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/src/main.ts b/src/main/nodejs/havelessbemore/src/main.ts index f7f544d..c704707 100644 --- a/src/main/nodejs/havelessbemore/src/main.ts +++ b/src/main/nodejs/havelessbemore/src/main.ts @@ -35,16 +35,22 @@ export async function run( maxWorkers = chunks.length; // Initialize data - const numVals = MAX_STATIONS * maxWorkers + 1; - const counts = new Uint32Array( - new SharedArrayBuffer(Uint32Array.BYTES_PER_ELEMENT * numVals), - ); - const minmaxes = new Int16Array( - new SharedArrayBuffer(2 * Int16Array.BYTES_PER_ELEMENT * numVals), - ); - const sums = new Float64Array( - new SharedArrayBuffer(Float64Array.BYTES_PER_ELEMENT * numVals), + const BPE = + // Count + Uint32Array.BYTES_PER_ELEMENT + + // Max + Int16Array.BYTES_PER_ELEMENT + + // Min + Int16Array.BYTES_PER_ELEMENT + + // Sum + Float64Array.BYTES_PER_ELEMENT; + const valuesBuffer = new SharedArrayBuffer( + BPE * (MAX_STATIONS * maxWorkers + 1), ); + const mins = new Int16Array(valuesBuffer); + const maxes = new Int16Array(valuesBuffer, Int16Array.BYTES_PER_ELEMENT); + const counts = new Uint32Array(valuesBuffer, Uint32Array.BYTES_PER_ELEMENT); + const sums = new Float64Array(valuesBuffer, Float64Array.BYTES_PER_ELEMENT); const tries: Int32Array[] = new Array(maxWorkers); // Create workers @@ -78,7 +84,8 @@ export async function run( end, filePath, id, - minmaxes, + maxes, + mins, start, sums, } as WorkerRequest); @@ -112,12 +119,12 @@ export async function run( out.end("}\n"); function mergeStations(ai: number, bi: number): void { - counts[ai] += counts[bi]; - sums[ai] += sums[bi]; - ai <<= 1; - bi <<= 1; - minmaxes[ai] = Math.min(minmaxes[ai], minmaxes[bi]); - minmaxes[ai + 1] = Math.max(minmaxes[ai + 1], minmaxes[bi + 1]); + ai <<= 3; + bi <<= 3; + mins[ai] = Math.min(mins[ai], mins[bi]); + maxes[ai] = Math.max(maxes[ai], maxes[bi]); + counts[ai >> 1] += counts[bi >> 1]; + sums[ai >> 2] += sums[bi >> 2]; } function printStation( @@ -126,14 +133,13 @@ export async function run( nameLen: number, vi: number, ): void { - const avg = Math.round(sums[vi] / counts[vi]); - vi <<= 1; + const avg = Math.round(sums[vi << 1] / counts[vi << 2]); stream.write(name.toString("utf8", 0, nameLen)); stream.write("="); - stream.write((minmaxes[vi] / 10).toFixed(1)); + stream.write((mins[vi << 3] / 10).toFixed(1)); stream.write("/"); stream.write((avg / 10).toFixed(1)); stream.write("/"); - stream.write((minmaxes[vi + 1] / 10).toFixed(1)); + stream.write((maxes[vi << 3] / 10).toFixed(1)); } } diff --git a/src/main/nodejs/havelessbemore/src/types/workerRequest.ts b/src/main/nodejs/havelessbemore/src/types/workerRequest.ts index 33485fb..88909f9 100644 --- a/src/main/nodejs/havelessbemore/src/types/workerRequest.ts +++ b/src/main/nodejs/havelessbemore/src/types/workerRequest.ts @@ -5,6 +5,7 @@ export interface WorkerRequest { start: number; // Shared memory counts: Uint32Array; - minmaxes: Int16Array; + maxes: Int16Array; + mins: Int16Array; sums: Float64Array; } diff --git a/src/main/nodejs/havelessbemore/src/worker.ts b/src/main/nodejs/havelessbemore/src/worker.ts index 66645da..65e70b3 100644 --- a/src/main/nodejs/havelessbemore/src/worker.ts +++ b/src/main/nodejs/havelessbemore/src/worker.ts @@ -19,7 +19,8 @@ export async function run({ start, // Shared memory counts, - minmaxes, + maxes, + mins, sums, }: WorkerRequest): Promise { // Check chunk size @@ -73,20 +74,18 @@ export async function run({ } function newStation(index: number, temp: number): void { - counts[index] = 1; - sums[index] = temp; - index <<= 1; - minmaxes[index] = temp; - minmaxes[index + 1] = temp; + mins[index << 3] = temp; + maxes[index << 3] = temp; + counts[index << 2] = 1; + sums[index << 1] = temp; } function updateStation(index: number, temp: number): void { - ++counts[index]; - sums[index] += temp; - index <<= 1; - minmaxes[index] = minmaxes[index] <= temp ? minmaxes[index] : temp; - ++index; - minmaxes[index] = minmaxes[index] >= temp ? minmaxes[index] : temp; + index <<= 3; + mins[index] = mins[index] <= temp ? mins[index] : temp; + maxes[index] = maxes[index] >= temp ? maxes[index] : temp; + ++counts[index >> 1]; + sums[index >> 2] += temp; } return { id, trie }; From 981cfe5fd0d14119a2bd73814ce523d18786dc20 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Thu, 23 May 2024 00:19:20 -0400 Subject: [PATCH 13/69] Rename utf8Trie constants again, Refactor main() --- src/main/nodejs/havelessbemore/dist/index.cjs | 107 ++++++++---------- .../nodejs/havelessbemore/dist/index.cjs.map | 2 +- src/main/nodejs/havelessbemore/dist/index.mjs | 107 ++++++++---------- .../nodejs/havelessbemore/dist/index.mjs.map | 2 +- .../havelessbemore/src/constants/utf8Trie.ts | 59 +++++----- src/main/nodejs/havelessbemore/src/main.ts | 21 +--- .../havelessbemore/src/utils/utf8Trie.ts | 67 ++++++----- src/main/nodejs/havelessbemore/src/worker.ts | 8 +- 8 files changed, 169 insertions(+), 204 deletions(-) diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs b/src/main/nodejs/havelessbemore/dist/index.cjs index a63332c..f87c8ab 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs +++ b/src/main/nodejs/havelessbemore/dist/index.cjs @@ -65,52 +65,52 @@ function getHighWaterMark(size) { return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX); } -const TRIE_NULL = 0; -const MIN_TRIE_SIZE = 524288; -const TRIE_GROWTH_FACTOR = 1.618; -const TRIE_CHILD_IDX_IDX = 0; -const TRIE_CHILD_IDX_MEM = 1; -const TRIE_CHILD_MEM = TRIE_CHILD_IDX_MEM; -const TRIE_RED_ID_IDX = 0; -const TRIE_RED_ID_MEM = 1; -const TRIE_RED_VALUE_IDX_IDX = 1; -const TRIE_RED_VALUE_IDX_MEM = 1; -const TRIE_RED_MEM = TRIE_RED_ID_MEM + TRIE_RED_VALUE_IDX_MEM; +const TRIE_DEFAULT_SIZE = 524288; +const TRIE_GROWTH_FACTOR = 1.6180339887; +const TRIE_PTR_IDX_IDX = 0; +const TRIE_PTR_IDX_MEM = 1; +const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM; +const TRIE_XPTR_ID_IDX = 0; +const TRIE_XPTR_ID_MEM = 1; +const TRIE_XPTR_IDX_IDX = 1; +const TRIE_XPTR_IDX_MEM = 1; +const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM; const TRIE_NODE_ID_IDX = 0; const TRIE_NODE_ID_MEM = 1; -const TRIE_NODE_VALUE_IDX_IDX = 1; -const TRIE_NODE_VALUE_IDX_MEM = 1; +const TRIE_NODE_VALUE_IDX = 1; +const TRIE_NODE_VALUE_MEM = 1; const TRIE_NODE_CHILDREN_IDX = 2; const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN; -const TRIE_NODE_CHILDREN_MEM = TRIE_CHILD_MEM * TRIE_NODE_CHILDREN_LEN; -const TRIE_NODE_MEM = TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_IDX_MEM + TRIE_NODE_CHILDREN_MEM; +const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN; +const TRIE_NODE_MEM = TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM; +const TRIE_NULL = 0; const TRIE_SIZE_IDX = 0; const TRIE_SIZE_MEM = 1; const TRIE_ROOT_IDX = 1; const TRIE_ROOT_MEM = TRIE_NODE_MEM; const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX; -const TRIE_HEADER_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM; +const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM; function add(trie, key, min, max) { let index = TRIE_ROOT_IDX; while (min < max) { - index += TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_MEM * (key[min++] - UTF8_B0_MIN); - let child = trie[index + TRIE_CHILD_IDX_IDX]; + index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN); + let child = trie[index + TRIE_PTR_IDX_IDX]; if (child === TRIE_NULL) { child = trie[TRIE_SIZE_IDX]; if (child + TRIE_NODE_MEM > trie.length) { trie = grow(trie, child + TRIE_NODE_MEM); } trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM; - trie[index + TRIE_CHILD_IDX_IDX] = child; + trie[index + TRIE_PTR_IDX_IDX] = child; trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX]; } index = child; } return [trie, index]; } -function createTrie(id = 0, size = MIN_TRIE_SIZE) { - const minSize = TRIE_HEADER_MEM; +function createTrie(id = 0, size = TRIE_DEFAULT_SIZE) { + const minSize = TRIE_MEM; const trie = new Int32Array(Math.max(minSize, size)); trie[TRIE_SIZE_IDX] = minSize; trie[TRIE_ID_IDX] = id; @@ -133,47 +133,47 @@ function mergeLeft(tries, at, bt, mergeFn) { const Q = queue.length; for (let q = 0; q < Q; ++q) { let [at2, ai, bt2, bi] = queue[q]; - const bvi = tries[bt2][bi + TRIE_NODE_VALUE_IDX_IDX]; + const bvi = tries[bt2][bi + TRIE_NODE_VALUE_IDX]; if (bvi !== TRIE_NULL) { - const avi = tries[at2][ai + TRIE_NODE_VALUE_IDX_IDX]; + const avi = tries[at2][ai + TRIE_NODE_VALUE_IDX]; if (avi !== TRIE_NULL) { mergeFn(avi, bvi); } else { - tries[at2][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi; + tries[at2][ai + TRIE_NODE_VALUE_IDX] = bvi; } } ai += TRIE_NODE_CHILDREN_IDX; bi += TRIE_NODE_CHILDREN_IDX; const bn = bi + TRIE_NODE_CHILDREN_MEM; while (bi < bn) { - let ri = tries[bt2][bi + TRIE_CHILD_IDX_IDX]; + let ri = tries[bt2][bi + TRIE_PTR_IDX_IDX]; if (ri === TRIE_NULL) { - ai += TRIE_CHILD_MEM; - bi += TRIE_CHILD_MEM; + ai += TRIE_PTR_MEM; + bi += TRIE_PTR_MEM; continue; } const rt = tries[bt2][ri + TRIE_NODE_ID_IDX]; if (bt2 !== rt) { - ri = tries[bt2][ri + TRIE_RED_VALUE_IDX_IDX]; + ri = tries[bt2][ri + TRIE_XPTR_IDX_IDX]; } - let li = tries[at2][ai + TRIE_CHILD_IDX_IDX]; + let li = tries[at2][ai + TRIE_PTR_IDX_IDX]; if (li === TRIE_NULL) { li = tries[at2][TRIE_SIZE_IDX]; - if (li + TRIE_RED_MEM > tries[at2].length) { - tries[at2] = grow(tries[at2], li + TRIE_RED_MEM); + if (li + TRIE_XPTR_MEM > tries[at2].length) { + tries[at2] = grow(tries[at2], li + TRIE_XPTR_MEM); } - tries[at2][TRIE_SIZE_IDX] += TRIE_RED_MEM; - tries[at2][li + TRIE_RED_ID_IDX] = rt; - tries[at2][li + TRIE_RED_VALUE_IDX_IDX] = ri; + tries[at2][TRIE_SIZE_IDX] += TRIE_XPTR_MEM; + tries[at2][li + TRIE_XPTR_ID_IDX] = rt; + tries[at2][li + TRIE_XPTR_IDX_IDX] = ri; } else { const lt = tries[at2][li + TRIE_NODE_ID_IDX]; if (at2 !== lt) { - ai = tries[at2][li + TRIE_RED_VALUE_IDX_IDX]; + ai = tries[at2][li + TRIE_XPTR_IDX_IDX]; } queue.push([lt, li, rt, ri]); } - ai += TRIE_CHILD_MEM; - bi += TRIE_CHILD_MEM; + ai += TRIE_PTR_MEM; + bi += TRIE_PTR_MEM; } } queue.splice(0, Q); @@ -190,20 +190,20 @@ function print(tries, key, trieIndex, stream, separator = "", callbackFn) { --top; continue; } - stack[top][1] += TRIE_CHILD_MEM; + stack[top][1] += TRIE_PTR_MEM; ++stack[top][2]; - let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX]; + let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX]; if (childI === TRIE_NULL) { continue; } const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX]; if (trieI !== childTrieI) { - childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX]; + childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX]; trieI = childTrieI; } key[top] = numChild + UTF8_B0_MIN; stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0]; - const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX_IDX]; + const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX]; if (valueIndex !== TRIE_NULL) { if (tail) { stream.write(separator); @@ -223,20 +223,11 @@ async function run$1(filePath, workerPath, maxWorkers, outPath = "") { CHUNK_SIZE_MIN ); maxWorkers = chunks.length; - const BPE = ( - // Count - Uint32Array.BYTES_PER_ELEMENT + // Max - Int16Array.BYTES_PER_ELEMENT + // Min - Int16Array.BYTES_PER_ELEMENT + // Sum - Float64Array.BYTES_PER_ELEMENT - ); - const valuesBuffer = new SharedArrayBuffer( - BPE * (MAX_STATIONS * maxWorkers + 1) - ); - const mins = new Int16Array(valuesBuffer); - const maxes = new Int16Array(valuesBuffer, Int16Array.BYTES_PER_ELEMENT); - const counts = new Uint32Array(valuesBuffer, Uint32Array.BYTES_PER_ELEMENT); - const sums = new Float64Array(valuesBuffer, Float64Array.BYTES_PER_ELEMENT); + const valBuf = new SharedArrayBuffer(MAX_STATIONS * maxWorkers + 1 << 4); + const mins = new Int16Array(valBuf); + const maxes = new Int16Array(valBuf, 2); + const counts = new Uint32Array(valBuf, 4); + const sums = new Float64Array(valBuf, 8); const tries = new Array(maxWorkers); const workers = new Array(maxWorkers); for (let i = 0; i < maxWorkers; ++i) { @@ -347,10 +338,10 @@ async function run({ const tempV = parseDouble(buffer, tempI, bufI); bufI = 0; [trie, leaf] = add(trie, buffer, 0, tempI); - if (trie[leaf + TRIE_NODE_VALUE_IDX_IDX] !== TRIE_NULL) { - updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV); + if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) { + updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV); } else { - trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations; + trie[leaf + TRIE_NODE_VALUE_IDX] = stations; newStation(stations++, tempV); } } diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs.map b/src/main/nodejs/havelessbemore/dist/index.cjs.map index 95cc035..0e60300 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.cjs.map @@ -1 +1 @@ -{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN } from \"./utf8\";\n\n// Trie static properties\n\n/**\n * Represents null / undefined.\n */\nexport const TRIE_NULL = 0;\n\n/**\n * The minimum size a trie.\n */\nexport const MIN_TRIE_SIZE = 524288; // 2 MiB\n\n/**\n * The default growth factor for growing the size of a trie.\n */\nexport const TRIE_GROWTH_FACTOR = 1.618; // ~phi\n\n/**\n * All trie properties are represented by 32 bits (4 bytes).\n */\nexport const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT;\n\n// Trie child pointer properties\n\nexport const TRIE_CHILD_IDX_IDX = 0;\nexport const TRIE_CHILD_IDX_MEM = 1;\n\nexport const TRIE_CHILD_MEM = TRIE_CHILD_IDX_MEM;\n\n// Trie redirect pointer properties\n\nexport const TRIE_RED_ID_IDX = 0;\nexport const TRIE_RED_ID_MEM = 1;\n\nexport const TRIE_RED_VALUE_IDX_IDX = 1;\nexport const TRIE_RED_VALUE_IDX_MEM = 1;\n\nexport const TRIE_RED_MEM = TRIE_RED_ID_MEM + TRIE_RED_VALUE_IDX_MEM;\n\n// Trie node properties\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\nexport const TRIE_NODE_VALUE_IDX_IDX = 1;\nexport const TRIE_NODE_VALUE_IDX_MEM = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_CHILD_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_IDX_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie properties\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_HEADER_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n MIN_TRIE_SIZE,\n TRIE_CHILD_MEM,\n TRIE_CHILD_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_HEADER_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_RED_MEM,\n TRIE_RED_VALUE_IDX_IDX,\n TRIE_RED_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_MEM * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_CHILD_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach and initialize node\n trie[index + TRIE_CHILD_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array {\n const minSize = TRIE_HEADER_MEM;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_CHILD_MEM;\n bi += TRIE_CHILD_MEM;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_CHILD_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_RED_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_RED_MEM);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_RED_MEM;\n // Add new redirect\n tries[at][li + TRIE_RED_ID_IDX] = rt;\n tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_CHILD_MEM;\n bi += TRIE_CHILD_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_CHILD_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_B0_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/utf8Trie\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const BPE =\n // Count\n Uint32Array.BYTES_PER_ELEMENT +\n // Max\n Int16Array.BYTES_PER_ELEMENT +\n // Min\n Int16Array.BYTES_PER_ELEMENT +\n // Sum\n Float64Array.BYTES_PER_ELEMENT;\n const valuesBuffer = new SharedArrayBuffer(\n BPE * (MAX_STATIONS * maxWorkers + 1),\n );\n const mins = new Int16Array(valuesBuffer);\n const maxes = new Int16Array(valuesBuffer, Int16Array.BYTES_PER_ELEMENT);\n const counts = new Uint32Array(valuesBuffer, Uint32Array.BYTES_PER_ELEMENT);\n const sums = new Float64Array(valuesBuffer, Float64Array.BYTES_PER_ELEMENT);\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n counts,\n end,\n filePath,\n id,\n maxes,\n mins,\n start,\n sums,\n } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n tries[res.id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 1; i < maxWorkers; ++i) {\n mergeLeft(tries, 0, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: WorkerRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [res.trie.buffer]);\n });\n}\n"],"names":["open","at","bt","run","Worker","createWriteStream","createReadStream","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN } from \"./utf8\";\n\n// Configurable constants\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 524288; // 2 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Internal trie pointer\n\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Cross-trie pointer (aka redirect)\n\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a null / undefined trie element.\n */\nexport const TRIE_NULL = 0;\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_PTR_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_XPTR_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach and initialize node\n trie[index + TRIE_PTR_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n const minSize = TRIE_MEM;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_PTR_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_PTR_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Add new redirect\n tries[at][li + TRIE_XPTR_ID_IDX] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_B0_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/utf8Trie\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n counts,\n end,\n filePath,\n id,\n maxes,\n mins,\n start,\n sums,\n } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n tries[res.id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 1; i < maxWorkers; ++i) {\n mergeLeft(tries, 0, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: WorkerRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [res.trie.buffer]);\n });\n}\n"],"names":["open","at","bt","run","Worker","createWriteStream","createReadStream","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index 9c2cb03..44d7e7f 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -62,52 +62,52 @@ function getHighWaterMark(size) { return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX); } -const TRIE_NULL = 0; -const MIN_TRIE_SIZE = 524288; -const TRIE_GROWTH_FACTOR = 1.618; -const TRIE_CHILD_IDX_IDX = 0; -const TRIE_CHILD_IDX_MEM = 1; -const TRIE_CHILD_MEM = TRIE_CHILD_IDX_MEM; -const TRIE_RED_ID_IDX = 0; -const TRIE_RED_ID_MEM = 1; -const TRIE_RED_VALUE_IDX_IDX = 1; -const TRIE_RED_VALUE_IDX_MEM = 1; -const TRIE_RED_MEM = TRIE_RED_ID_MEM + TRIE_RED_VALUE_IDX_MEM; +const TRIE_DEFAULT_SIZE = 524288; +const TRIE_GROWTH_FACTOR = 1.6180339887; +const TRIE_PTR_IDX_IDX = 0; +const TRIE_PTR_IDX_MEM = 1; +const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM; +const TRIE_XPTR_ID_IDX = 0; +const TRIE_XPTR_ID_MEM = 1; +const TRIE_XPTR_IDX_IDX = 1; +const TRIE_XPTR_IDX_MEM = 1; +const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM; const TRIE_NODE_ID_IDX = 0; const TRIE_NODE_ID_MEM = 1; -const TRIE_NODE_VALUE_IDX_IDX = 1; -const TRIE_NODE_VALUE_IDX_MEM = 1; +const TRIE_NODE_VALUE_IDX = 1; +const TRIE_NODE_VALUE_MEM = 1; const TRIE_NODE_CHILDREN_IDX = 2; const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN; -const TRIE_NODE_CHILDREN_MEM = TRIE_CHILD_MEM * TRIE_NODE_CHILDREN_LEN; -const TRIE_NODE_MEM = TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_IDX_MEM + TRIE_NODE_CHILDREN_MEM; +const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN; +const TRIE_NODE_MEM = TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM; +const TRIE_NULL = 0; const TRIE_SIZE_IDX = 0; const TRIE_SIZE_MEM = 1; const TRIE_ROOT_IDX = 1; const TRIE_ROOT_MEM = TRIE_NODE_MEM; const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX; -const TRIE_HEADER_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM; +const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM; function add(trie, key, min, max) { let index = TRIE_ROOT_IDX; while (min < max) { - index += TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_MEM * (key[min++] - UTF8_B0_MIN); - let child = trie[index + TRIE_CHILD_IDX_IDX]; + index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN); + let child = trie[index + TRIE_PTR_IDX_IDX]; if (child === TRIE_NULL) { child = trie[TRIE_SIZE_IDX]; if (child + TRIE_NODE_MEM > trie.length) { trie = grow(trie, child + TRIE_NODE_MEM); } trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM; - trie[index + TRIE_CHILD_IDX_IDX] = child; + trie[index + TRIE_PTR_IDX_IDX] = child; trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX]; } index = child; } return [trie, index]; } -function createTrie(id = 0, size = MIN_TRIE_SIZE) { - const minSize = TRIE_HEADER_MEM; +function createTrie(id = 0, size = TRIE_DEFAULT_SIZE) { + const minSize = TRIE_MEM; const trie = new Int32Array(Math.max(minSize, size)); trie[TRIE_SIZE_IDX] = minSize; trie[TRIE_ID_IDX] = id; @@ -130,47 +130,47 @@ function mergeLeft(tries, at, bt, mergeFn) { const Q = queue.length; for (let q = 0; q < Q; ++q) { let [at2, ai, bt2, bi] = queue[q]; - const bvi = tries[bt2][bi + TRIE_NODE_VALUE_IDX_IDX]; + const bvi = tries[bt2][bi + TRIE_NODE_VALUE_IDX]; if (bvi !== TRIE_NULL) { - const avi = tries[at2][ai + TRIE_NODE_VALUE_IDX_IDX]; + const avi = tries[at2][ai + TRIE_NODE_VALUE_IDX]; if (avi !== TRIE_NULL) { mergeFn(avi, bvi); } else { - tries[at2][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi; + tries[at2][ai + TRIE_NODE_VALUE_IDX] = bvi; } } ai += TRIE_NODE_CHILDREN_IDX; bi += TRIE_NODE_CHILDREN_IDX; const bn = bi + TRIE_NODE_CHILDREN_MEM; while (bi < bn) { - let ri = tries[bt2][bi + TRIE_CHILD_IDX_IDX]; + let ri = tries[bt2][bi + TRIE_PTR_IDX_IDX]; if (ri === TRIE_NULL) { - ai += TRIE_CHILD_MEM; - bi += TRIE_CHILD_MEM; + ai += TRIE_PTR_MEM; + bi += TRIE_PTR_MEM; continue; } const rt = tries[bt2][ri + TRIE_NODE_ID_IDX]; if (bt2 !== rt) { - ri = tries[bt2][ri + TRIE_RED_VALUE_IDX_IDX]; + ri = tries[bt2][ri + TRIE_XPTR_IDX_IDX]; } - let li = tries[at2][ai + TRIE_CHILD_IDX_IDX]; + let li = tries[at2][ai + TRIE_PTR_IDX_IDX]; if (li === TRIE_NULL) { li = tries[at2][TRIE_SIZE_IDX]; - if (li + TRIE_RED_MEM > tries[at2].length) { - tries[at2] = grow(tries[at2], li + TRIE_RED_MEM); + if (li + TRIE_XPTR_MEM > tries[at2].length) { + tries[at2] = grow(tries[at2], li + TRIE_XPTR_MEM); } - tries[at2][TRIE_SIZE_IDX] += TRIE_RED_MEM; - tries[at2][li + TRIE_RED_ID_IDX] = rt; - tries[at2][li + TRIE_RED_VALUE_IDX_IDX] = ri; + tries[at2][TRIE_SIZE_IDX] += TRIE_XPTR_MEM; + tries[at2][li + TRIE_XPTR_ID_IDX] = rt; + tries[at2][li + TRIE_XPTR_IDX_IDX] = ri; } else { const lt = tries[at2][li + TRIE_NODE_ID_IDX]; if (at2 !== lt) { - ai = tries[at2][li + TRIE_RED_VALUE_IDX_IDX]; + ai = tries[at2][li + TRIE_XPTR_IDX_IDX]; } queue.push([lt, li, rt, ri]); } - ai += TRIE_CHILD_MEM; - bi += TRIE_CHILD_MEM; + ai += TRIE_PTR_MEM; + bi += TRIE_PTR_MEM; } } queue.splice(0, Q); @@ -187,20 +187,20 @@ function print(tries, key, trieIndex, stream, separator = "", callbackFn) { --top; continue; } - stack[top][1] += TRIE_CHILD_MEM; + stack[top][1] += TRIE_PTR_MEM; ++stack[top][2]; - let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX]; + let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX]; if (childI === TRIE_NULL) { continue; } const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX]; if (trieI !== childTrieI) { - childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX]; + childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX]; trieI = childTrieI; } key[top] = numChild + UTF8_B0_MIN; stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0]; - const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX_IDX]; + const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX]; if (valueIndex !== TRIE_NULL) { if (tail) { stream.write(separator); @@ -220,20 +220,11 @@ async function run$1(filePath, workerPath, maxWorkers, outPath = "") { CHUNK_SIZE_MIN ); maxWorkers = chunks.length; - const BPE = ( - // Count - Uint32Array.BYTES_PER_ELEMENT + // Max - Int16Array.BYTES_PER_ELEMENT + // Min - Int16Array.BYTES_PER_ELEMENT + // Sum - Float64Array.BYTES_PER_ELEMENT - ); - const valuesBuffer = new SharedArrayBuffer( - BPE * (MAX_STATIONS * maxWorkers + 1) - ); - const mins = new Int16Array(valuesBuffer); - const maxes = new Int16Array(valuesBuffer, Int16Array.BYTES_PER_ELEMENT); - const counts = new Uint32Array(valuesBuffer, Uint32Array.BYTES_PER_ELEMENT); - const sums = new Float64Array(valuesBuffer, Float64Array.BYTES_PER_ELEMENT); + const valBuf = new SharedArrayBuffer(MAX_STATIONS * maxWorkers + 1 << 4); + const mins = new Int16Array(valBuf); + const maxes = new Int16Array(valBuf, 2); + const counts = new Uint32Array(valBuf, 4); + const sums = new Float64Array(valBuf, 8); const tries = new Array(maxWorkers); const workers = new Array(maxWorkers); for (let i = 0; i < maxWorkers; ++i) { @@ -344,10 +335,10 @@ async function run({ const tempV = parseDouble(buffer, tempI, bufI); bufI = 0; [trie, leaf] = add(trie, buffer, 0, tempI); - if (trie[leaf + TRIE_NODE_VALUE_IDX_IDX] !== TRIE_NULL) { - updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV); + if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) { + updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV); } else { - trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations; + trie[leaf + TRIE_NODE_VALUE_IDX] = stations; newStation(stations++, tempV); } } diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index 4d27353..54d6727 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1 +1 @@ -{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN } from \"./utf8\";\n\n// Trie static properties\n\n/**\n * Represents null / undefined.\n */\nexport const TRIE_NULL = 0;\n\n/**\n * The minimum size a trie.\n */\nexport const MIN_TRIE_SIZE = 524288; // 2 MiB\n\n/**\n * The default growth factor for growing the size of a trie.\n */\nexport const TRIE_GROWTH_FACTOR = 1.618; // ~phi\n\n/**\n * All trie properties are represented by 32 bits (4 bytes).\n */\nexport const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT;\n\n// Trie child pointer properties\n\nexport const TRIE_CHILD_IDX_IDX = 0;\nexport const TRIE_CHILD_IDX_MEM = 1;\n\nexport const TRIE_CHILD_MEM = TRIE_CHILD_IDX_MEM;\n\n// Trie redirect pointer properties\n\nexport const TRIE_RED_ID_IDX = 0;\nexport const TRIE_RED_ID_MEM = 1;\n\nexport const TRIE_RED_VALUE_IDX_IDX = 1;\nexport const TRIE_RED_VALUE_IDX_MEM = 1;\n\nexport const TRIE_RED_MEM = TRIE_RED_ID_MEM + TRIE_RED_VALUE_IDX_MEM;\n\n// Trie node properties\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\nexport const TRIE_NODE_VALUE_IDX_IDX = 1;\nexport const TRIE_NODE_VALUE_IDX_MEM = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_CHILD_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_IDX_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie properties\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_HEADER_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n MIN_TRIE_SIZE,\n TRIE_CHILD_MEM,\n TRIE_CHILD_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_HEADER_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_RED_MEM,\n TRIE_RED_VALUE_IDX_IDX,\n TRIE_RED_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_MEM * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_CHILD_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach and initialize node\n trie[index + TRIE_CHILD_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array {\n const minSize = TRIE_HEADER_MEM;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_CHILD_MEM;\n bi += TRIE_CHILD_MEM;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_CHILD_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_RED_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_RED_MEM);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_RED_MEM;\n // Add new redirect\n tries[at][li + TRIE_RED_ID_IDX] = rt;\n tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_CHILD_MEM;\n bi += TRIE_CHILD_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_CHILD_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_B0_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/utf8Trie\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const BPE =\n // Count\n Uint32Array.BYTES_PER_ELEMENT +\n // Max\n Int16Array.BYTES_PER_ELEMENT +\n // Min\n Int16Array.BYTES_PER_ELEMENT +\n // Sum\n Float64Array.BYTES_PER_ELEMENT;\n const valuesBuffer = new SharedArrayBuffer(\n BPE * (MAX_STATIONS * maxWorkers + 1),\n );\n const mins = new Int16Array(valuesBuffer);\n const maxes = new Int16Array(valuesBuffer, Int16Array.BYTES_PER_ELEMENT);\n const counts = new Uint32Array(valuesBuffer, Uint32Array.BYTES_PER_ELEMENT);\n const sums = new Float64Array(valuesBuffer, Float64Array.BYTES_PER_ELEMENT);\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n counts,\n end,\n filePath,\n id,\n maxes,\n mins,\n start,\n sums,\n } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n tries[res.id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 1; i < maxWorkers; ++i) {\n mergeLeft(tries, 0, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: WorkerRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [res.trie.buffer]);\n });\n}\n"],"names":["at","bt","run","runMain","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN } from \"./utf8\";\n\n// Configurable constants\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 524288; // 2 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Internal trie pointer\n\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Cross-trie pointer (aka redirect)\n\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a null / undefined trie element.\n */\nexport const TRIE_NULL = 0;\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_PTR_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_XPTR_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach and initialize node\n trie[index + TRIE_PTR_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n const minSize = TRIE_MEM;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_PTR_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_PTR_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Add new redirect\n tries[at][li + TRIE_XPTR_ID_IDX] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_B0_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/utf8Trie\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n counts,\n end,\n filePath,\n id,\n maxes,\n mins,\n start,\n sums,\n } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n tries[res.id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 1; i < maxWorkers; ++i) {\n mergeLeft(tries, 0, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: WorkerRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [res.trie.buffer]);\n });\n}\n"],"names":["at","bt","run","runMain","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts b/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts index 0ce8d8c..202c6b2 100644 --- a/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts +++ b/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts @@ -1,60 +1,55 @@ import { UTF8_B0_2B_LEN } from "./utf8"; -// Trie static properties +// Configurable constants /** - * Represents null / undefined. + * The default initial size of a trie. */ -export const TRIE_NULL = 0; - -/** - * The minimum size a trie. - */ -export const MIN_TRIE_SIZE = 524288; // 2 MiB +export const TRIE_DEFAULT_SIZE = 524288; // 2 MiB /** - * The default growth factor for growing the size of a trie. + * The growth factor for resizing a trie (Approx. Phi) */ -export const TRIE_GROWTH_FACTOR = 1.618; // ~phi +export const TRIE_GROWTH_FACTOR = 1.6180339887; -/** - * All trie properties are represented by 32 bits (4 bytes). - */ -export const TRIE_UNIT = Int32Array.BYTES_PER_ELEMENT; +// Internal trie pointer -// Trie child pointer properties +export const TRIE_PTR_IDX_IDX = 0; +export const TRIE_PTR_IDX_MEM = 1; -export const TRIE_CHILD_IDX_IDX = 0; -export const TRIE_CHILD_IDX_MEM = 1; +export const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM; -export const TRIE_CHILD_MEM = TRIE_CHILD_IDX_MEM; +// Cross-trie pointer (aka redirect) -// Trie redirect pointer properties +export const TRIE_XPTR_ID_IDX = 0; +export const TRIE_XPTR_ID_MEM = 1; -export const TRIE_RED_ID_IDX = 0; -export const TRIE_RED_ID_MEM = 1; +export const TRIE_XPTR_IDX_IDX = 1; +export const TRIE_XPTR_IDX_MEM = 1; -export const TRIE_RED_VALUE_IDX_IDX = 1; -export const TRIE_RED_VALUE_IDX_MEM = 1; +export const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM; -export const TRIE_RED_MEM = TRIE_RED_ID_MEM + TRIE_RED_VALUE_IDX_MEM; - -// Trie node properties +// Trie node export const TRIE_NODE_ID_IDX = 0; export const TRIE_NODE_ID_MEM = 1; -export const TRIE_NODE_VALUE_IDX_IDX = 1; -export const TRIE_NODE_VALUE_IDX_MEM = 1; +export const TRIE_NODE_VALUE_IDX = 1; +export const TRIE_NODE_VALUE_MEM = 1; export const TRIE_NODE_CHILDREN_IDX = 2; export const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN; -export const TRIE_NODE_CHILDREN_MEM = TRIE_CHILD_MEM * TRIE_NODE_CHILDREN_LEN; +export const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN; export const TRIE_NODE_MEM = - TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_IDX_MEM + TRIE_NODE_CHILDREN_MEM; + TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM; + +// Trie -// Trie properties +/** + * Represents a null / undefined trie element. + */ +export const TRIE_NULL = 0; export const TRIE_SIZE_IDX = 0; export const TRIE_SIZE_MEM = 1; @@ -63,4 +58,4 @@ export const TRIE_ROOT_IDX = 1; export const TRIE_ROOT_MEM = TRIE_NODE_MEM; export const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX; -export const TRIE_HEADER_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM; +export const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM; diff --git a/src/main/nodejs/havelessbemore/src/main.ts b/src/main/nodejs/havelessbemore/src/main.ts index c704707..4d063e7 100644 --- a/src/main/nodejs/havelessbemore/src/main.ts +++ b/src/main/nodejs/havelessbemore/src/main.ts @@ -35,22 +35,11 @@ export async function run( maxWorkers = chunks.length; // Initialize data - const BPE = - // Count - Uint32Array.BYTES_PER_ELEMENT + - // Max - Int16Array.BYTES_PER_ELEMENT + - // Min - Int16Array.BYTES_PER_ELEMENT + - // Sum - Float64Array.BYTES_PER_ELEMENT; - const valuesBuffer = new SharedArrayBuffer( - BPE * (MAX_STATIONS * maxWorkers + 1), - ); - const mins = new Int16Array(valuesBuffer); - const maxes = new Int16Array(valuesBuffer, Int16Array.BYTES_PER_ELEMENT); - const counts = new Uint32Array(valuesBuffer, Uint32Array.BYTES_PER_ELEMENT); - const sums = new Float64Array(valuesBuffer, Float64Array.BYTES_PER_ELEMENT); + const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4); + const mins = new Int16Array(valBuf); + const maxes = new Int16Array(valBuf, 2); + const counts = new Uint32Array(valBuf, 4); + const sums = new Float64Array(valBuf, 8); const tries: Int32Array[] = new Array(maxWorkers); // Create workers diff --git a/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts b/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts index 589b123..cf36e04 100644 --- a/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts +++ b/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts @@ -1,21 +1,21 @@ import { WriteStream } from "node:fs"; import { - MIN_TRIE_SIZE, - TRIE_CHILD_MEM, - TRIE_CHILD_IDX_IDX, + TRIE_DEFAULT_SIZE, + TRIE_PTR_MEM, + TRIE_PTR_IDX_IDX, TRIE_GROWTH_FACTOR, - TRIE_HEADER_MEM, + TRIE_MEM, TRIE_ID_IDX, TRIE_NODE_CHILDREN_IDX, TRIE_NODE_ID_IDX, - TRIE_NODE_VALUE_IDX_IDX, + TRIE_NODE_VALUE_IDX, TRIE_NULL, TRIE_ROOT_IDX, TRIE_SIZE_IDX, - TRIE_RED_MEM, - TRIE_RED_VALUE_IDX_IDX, - TRIE_RED_ID_IDX, + TRIE_XPTR_MEM, + TRIE_XPTR_IDX_IDX, + TRIE_XPTR_ID_IDX, TRIE_NODE_MEM, TRIE_NODE_CHILDREN_MEM, TRIE_NODE_CHILDREN_LEN, @@ -30,9 +30,8 @@ export function add( ): [Int32Array, number] { let index = TRIE_ROOT_IDX; while (min < max) { - index += - TRIE_NODE_CHILDREN_IDX + TRIE_CHILD_MEM * (key[min++] - UTF8_B0_MIN); - let child = trie[index + TRIE_CHILD_IDX_IDX]; + index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN); + let child = trie[index + TRIE_PTR_IDX_IDX]; if (child === TRIE_NULL) { // Allocate new node child = trie[TRIE_SIZE_IDX]; @@ -41,7 +40,7 @@ export function add( } trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM; // Attach and initialize node - trie[index + TRIE_CHILD_IDX_IDX] = child; + trie[index + TRIE_PTR_IDX_IDX] = child; trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX]; } index = child; @@ -50,8 +49,8 @@ export function add( return [trie, index]; } -export function createTrie(id = 0, size = MIN_TRIE_SIZE): Int32Array { - const minSize = TRIE_HEADER_MEM; +export function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array { + const minSize = TRIE_MEM; const trie = new Int32Array(Math.max(minSize, size)); trie[TRIE_SIZE_IDX] = minSize; trie[TRIE_ID_IDX] = id; @@ -84,14 +83,14 @@ export function mergeLeft( let [at, ai, bt, bi] = queue[q]; // If right value is not null - const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX_IDX]; + const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX]; if (bvi !== TRIE_NULL) { // If left value is not null - const avi = tries[at][ai + TRIE_NODE_VALUE_IDX_IDX]; + const avi = tries[at][ai + TRIE_NODE_VALUE_IDX]; if (avi !== TRIE_NULL) { mergeFn(avi, bvi); } else { - tries[at][ai + TRIE_NODE_VALUE_IDX_IDX] = bvi; + tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi; } } @@ -103,45 +102,45 @@ export function mergeLeft( const bn = bi + TRIE_NODE_CHILDREN_MEM; while (bi < bn) { // If right child is null - let ri = tries[bt][bi + TRIE_CHILD_IDX_IDX]; + let ri = tries[bt][bi + TRIE_PTR_IDX_IDX]; if (ri === TRIE_NULL) { // Move to next children - ai += TRIE_CHILD_MEM; - bi += TRIE_CHILD_MEM; + ai += TRIE_PTR_MEM; + bi += TRIE_PTR_MEM; continue; } // Resolve right child if redirect const rt = tries[bt][ri + TRIE_NODE_ID_IDX]; if (bt !== rt) { - ri = tries[bt][ri + TRIE_RED_VALUE_IDX_IDX]; + ri = tries[bt][ri + TRIE_XPTR_IDX_IDX]; } // If left child is null - let li = tries[at][ai + TRIE_CHILD_IDX_IDX]; + let li = tries[at][ai + TRIE_PTR_IDX_IDX]; if (li === TRIE_NULL) { // Allocate new redirect in left trie li = tries[at][TRIE_SIZE_IDX]; - if (li + TRIE_RED_MEM > tries[at].length) { - tries[at] = grow(tries[at], li + TRIE_RED_MEM); + if (li + TRIE_XPTR_MEM > tries[at].length) { + tries[at] = grow(tries[at], li + TRIE_XPTR_MEM); } - tries[at][TRIE_SIZE_IDX] += TRIE_RED_MEM; + tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM; // Add new redirect - tries[at][li + TRIE_RED_ID_IDX] = rt; - tries[at][li + TRIE_RED_VALUE_IDX_IDX] = ri; + tries[at][li + TRIE_XPTR_ID_IDX] = rt; + tries[at][li + TRIE_XPTR_IDX_IDX] = ri; } else { // Resolve left child if redirect const lt = tries[at][li + TRIE_NODE_ID_IDX]; if (at !== lt) { - ai = tries[at][li + TRIE_RED_VALUE_IDX_IDX]; + ai = tries[at][li + TRIE_XPTR_IDX_IDX]; } // Merge children queue.push([lt, li, rt, ri]); } // Move to next children - ai += TRIE_CHILD_MEM; - bi += TRIE_CHILD_MEM; + ai += TRIE_PTR_MEM; + bi += TRIE_PTR_MEM; } } queue.splice(0, Q); @@ -176,11 +175,11 @@ export function print( } // Update stack top - stack[top][1] += TRIE_CHILD_MEM; + stack[top][1] += TRIE_PTR_MEM; ++stack[top][2]; // Check if child exists - let childI = tries[trieI][childPtr + TRIE_CHILD_IDX_IDX]; + let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX]; if (childI === TRIE_NULL) { continue; } @@ -188,7 +187,7 @@ export function print( // Resolve redirect, if any const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX]; if (trieI !== childTrieI) { - childI = tries[trieI][childI + TRIE_RED_VALUE_IDX_IDX]; + childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX]; trieI = childTrieI; } @@ -197,7 +196,7 @@ export function print( stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0]; // Print value, if any - const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX_IDX]; + const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX]; if (valueIndex !== TRIE_NULL) { // Print separator if not first value if (tail) { diff --git a/src/main/nodejs/havelessbemore/src/worker.ts b/src/main/nodejs/havelessbemore/src/worker.ts index 65e70b3..5f8f367 100644 --- a/src/main/nodejs/havelessbemore/src/worker.ts +++ b/src/main/nodejs/havelessbemore/src/worker.ts @@ -8,7 +8,7 @@ import { CHAR_NEWLINE } from "./constants/utf8"; import { CHAR_MINUS } from "./constants/utf8"; import { ENTRY_MAX_LEN, MAX_STATIONS } from "./constants/constraints"; import { CHAR_ZERO_11, CHAR_ZERO_111 } from "./constants/stream"; -import { TRIE_NODE_VALUE_IDX_IDX, TRIE_NULL } from "./constants/utf8Trie"; +import { TRIE_NODE_VALUE_IDX, TRIE_NULL } from "./constants/utf8Trie"; import { getHighWaterMark } from "./utils/stream"; import { add, createTrie } from "./utils/utf8Trie"; @@ -61,12 +61,12 @@ export async function run({ // Add the station's name to the trie and get leaf index [trie, leaf] = add(trie, buffer, 0, tempI); // If the station existed - if (trie[leaf + TRIE_NODE_VALUE_IDX_IDX] !== TRIE_NULL) { + if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) { // Update the station's value - updateStation(trie[leaf + TRIE_NODE_VALUE_IDX_IDX], tempV); + updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV); } else { // Add the new station's value - trie[leaf + TRIE_NODE_VALUE_IDX_IDX] = stations; + trie[leaf + TRIE_NODE_VALUE_IDX] = stations; newStation(stations++, tempV); } } From ea5d0c80791a5f5b6ffdde52a5c24a2ec6bbed19 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Thu, 23 May 2024 08:58:53 -0400 Subject: [PATCH 14/69] Parallelize trie merging --- src/main/nodejs/havelessbemore/dist/index.cjs | 74 ++++++++++++++----- .../nodejs/havelessbemore/dist/index.cjs.map | 2 +- src/main/nodejs/havelessbemore/dist/index.mjs | 74 ++++++++++++++----- .../nodejs/havelessbemore/dist/index.mjs.map | 2 +- src/main/nodejs/havelessbemore/src/index.ts | 19 +++-- src/main/nodejs/havelessbemore/src/main.ts | 53 ++++++++----- .../havelessbemore/src/types/mergeRequest.ts | 13 ++++ .../havelessbemore/src/types/mergeResponse.ts | 7 ++ .../havelessbemore/src/types/message.ts | 4 + .../{workerRequest.ts => processRequest.ts} | 5 +- .../src/types/processResponse.ts | 7 ++ .../src/types/workerResponse.ts | 4 - .../havelessbemore/src/utils/utf8Trie.ts | 8 +- src/main/nodejs/havelessbemore/src/worker.ts | 27 +++++-- 14 files changed, 217 insertions(+), 82 deletions(-) create mode 100644 src/main/nodejs/havelessbemore/src/types/mergeRequest.ts create mode 100644 src/main/nodejs/havelessbemore/src/types/mergeResponse.ts create mode 100644 src/main/nodejs/havelessbemore/src/types/message.ts rename src/main/nodejs/havelessbemore/src/types/{workerRequest.ts => processRequest.ts} (60%) create mode 100644 src/main/nodejs/havelessbemore/src/types/processResponse.ts delete mode 100644 src/main/nodejs/havelessbemore/src/types/workerResponse.ts diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs b/src/main/nodejs/havelessbemore/dist/index.cjs index f87c8ab..c0ca613 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs +++ b/src/main/nodejs/havelessbemore/dist/index.cjs @@ -110,16 +110,18 @@ function add(trie, key, min, max) { return [trie, index]; } function createTrie(id = 0, size = TRIE_DEFAULT_SIZE) { - const minSize = TRIE_MEM; - const trie = new Int32Array(Math.max(minSize, size)); - trie[TRIE_SIZE_IDX] = minSize; + size = Math.max(TRIE_MEM, size); + const buffer = new SharedArrayBuffer(size << 2); + const trie = new Int32Array(buffer); + trie[TRIE_SIZE_IDX] = TRIE_MEM; trie[TRIE_ID_IDX] = id; return trie; } function grow(trie, minSize = 0) { const length = trie[TRIE_SIZE_IDX]; minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR)); - const next = new Int32Array(minSize); + const buffer = new SharedArrayBuffer(minSize << 2); + const next = new Int32Array(buffer); for (let i = 0; i < length; ++i) { next[i] = trie[i]; } @@ -253,6 +255,7 @@ async function run$1(filePath, workerPath, maxWorkers, outPath = "") { tasks[i] = new Promise((resolve) => { worker.once("message", resolve); worker.postMessage({ + type: "process_request", counts, end, filePath, @@ -267,12 +270,33 @@ async function run$1(filePath, workerPath, maxWorkers, outPath = "") { for await (const res of tasks) { tries[res.id] = res.trie; } + for (let i = 0, j = maxWorkers - 1; i < j; i = 0) { + const merges = []; + for (; i < j; ++i) { + const a = i; + const b = j--; + const worker = workers[i]; + merges.push(new Promise((resolve) => { + worker.once("message", resolve); + worker.postMessage({ + type: "merge_request", + a, + b, + counts, + maxes, + mins, + sums, + tries + }); + })); + } + for await (const res of merges) { + tries[res.id] = res.trie; + } + } for (let i = 0; i < maxWorkers; ++i) { await workers[i].terminate(); } - for (let i = 1; i < maxWorkers; ++i) { - mergeLeft(tries, 0, i, mergeStations); - } const out = node_fs.createWriteStream(outPath, { fd: outPath.length < 1 ? 1 : void 0, flags: "a", @@ -282,14 +306,6 @@ async function run$1(filePath, workerPath, maxWorkers, outPath = "") { out.write("{"); print(tries, buffer, 0, out, ", ", printStation); out.end("}\n"); - function mergeStations(ai, bi) { - ai <<= 3; - bi <<= 3; - mins[ai] = Math.min(mins[ai], mins[bi]); - maxes[ai] = Math.max(maxes[ai], maxes[bi]); - counts[ai >> 1] += counts[bi >> 1]; - sums[ai >> 2] += sums[bi >> 2]; - } function printStation(stream, name, nameLen, vi) { const avg = Math.round(sums[vi << 1] / counts[vi << 2]); stream.write(name.toString("utf8", 0, nameLen)); @@ -314,7 +330,7 @@ async function run({ sums }) { if (start >= end) { - return { id, trie: createTrie(id, 0) }; + return { type: "process_response", id, trie: createTrie(id, 0) }; } let trie = createTrie(id); let stations = id * MAX_STATIONS + 1; @@ -360,7 +376,7 @@ async function run({ ++counts[index >> 1]; sums[index >> 2] += temp; } - return { id, trie }; + return { type: "process_response", id, trie }; } function parseDouble(b, min, max) { if (b[min] === CHAR_MINUS) { @@ -369,14 +385,32 @@ function parseDouble(b, min, max) { } return min + 4 > max ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11 : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111; } +function merge({ a, b, tries, counts, maxes, mins, sums }) { + mergeLeft(tries, a, b, mergeStations); + function mergeStations(ai, bi) { + ai <<= 3; + bi <<= 3; + mins[ai] = Math.min(mins[ai], mins[bi]); + maxes[ai] = Math.max(maxes[ai], maxes[bi]); + counts[ai >> 1] += counts[bi >> 1]; + sums[ai >> 2] += sums[bi >> 2]; + } + return { type: "merge_response", id: a, trie: tries[a] }; +} if (node_worker_threads.isMainThread) { const workerPath = node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))); run$1(process.argv[2], workerPath, node_os.availableParallelism()); } else { - node_worker_threads.parentPort.addListener("message", async (req) => { - const res = await run(req); - node_worker_threads.parentPort.postMessage(res, [res.trie.buffer]); + node_worker_threads.parentPort.addListener("message", async (msg) => { + if (msg.type === "process_request") { + const res = await run(msg); + node_worker_threads.parentPort.postMessage(res); + } + if (msg.type === "merge_request") { + const res = merge(msg); + node_worker_threads.parentPort.postMessage(res); + } }); } //# sourceMappingURL=index.cjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs.map b/src/main/nodejs/havelessbemore/dist/index.cjs.map index 0e60300..dc8ed48 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.cjs.map @@ -1 +1 @@ -{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN } from \"./utf8\";\n\n// Configurable constants\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 524288; // 2 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Internal trie pointer\n\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Cross-trie pointer (aka redirect)\n\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a null / undefined trie element.\n */\nexport const TRIE_NULL = 0;\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_PTR_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_XPTR_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach and initialize node\n trie[index + TRIE_PTR_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n const minSize = TRIE_MEM;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_PTR_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_PTR_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Add new redirect\n tries[at][li + TRIE_XPTR_ID_IDX] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_B0_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/utf8Trie\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n counts,\n end,\n filePath,\n id,\n maxes,\n mins,\n start,\n sums,\n } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n tries[res.id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 1; i < maxWorkers; ++i) {\n mergeLeft(tries, 0, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: WorkerRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [res.trie.buffer]);\n });\n}\n"],"names":["open","at","bt","run","Worker","createWriteStream","createReadStream","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN } from \"./utf8\";\n\n// Configurable constants\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 524288; // 2 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Internal trie pointer\n\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Cross-trie pointer (aka redirect)\n\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a null / undefined trie element.\n */\nexport const TRIE_NULL = 0;\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_PTR_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_XPTR_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach and initialize node\n trie[index + TRIE_PTR_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const buffer = new SharedArrayBuffer(size << 2);\n const trie = new Int32Array(buffer);\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const buffer = new SharedArrayBuffer(minSize << 2);\n const next = new Int32Array(buffer);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_PTR_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_PTR_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Add new redirect\n tries[at][li + TRIE_XPTR_ID_IDX] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_B0_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n type: \"process_request\",\n counts,\n end,\n filePath,\n id,\n maxes,\n mins,\n start,\n sums,\n } as ProcessRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n tries[res.id] = res.trie;\n }\n\n // Merge tries\n for (let i = 0, j = maxWorkers - 1; i < j; i = 0) {\n const merges: Promise[] = [];\n for (; i < j; ++i) {\n const a = i;\n const b = j--;\n const worker = workers[i];\n merges.push(new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n } as MergeRequest);\n }));\n }\n for await (const res of merges) {\n tries[res.id] = res.trie;\n }\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\nexport function merge({a, b, tries, counts, maxes, mins, sums}: MergeRequest): MergeResponse {\n mergeLeft(tries, a, b, mergeStations);\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n return { type: \"merge_response\", id: a, trie: tries[a] };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n const res = await runWorker(msg as ProcessRequest);\n parentPort!.postMessage(res);\n }\n if (msg.type === \"merge_request\") {\n const res = merge(msg as MergeRequest);\n parentPort!.postMessage(res);\n }\n });\n}\n"],"names":["open","at","bt","run","Worker","createWriteStream","createReadStream","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index 44d7e7f..9e2d2df 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -107,16 +107,18 @@ function add(trie, key, min, max) { return [trie, index]; } function createTrie(id = 0, size = TRIE_DEFAULT_SIZE) { - const minSize = TRIE_MEM; - const trie = new Int32Array(Math.max(minSize, size)); - trie[TRIE_SIZE_IDX] = minSize; + size = Math.max(TRIE_MEM, size); + const buffer = new SharedArrayBuffer(size << 2); + const trie = new Int32Array(buffer); + trie[TRIE_SIZE_IDX] = TRIE_MEM; trie[TRIE_ID_IDX] = id; return trie; } function grow(trie, minSize = 0) { const length = trie[TRIE_SIZE_IDX]; minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR)); - const next = new Int32Array(minSize); + const buffer = new SharedArrayBuffer(minSize << 2); + const next = new Int32Array(buffer); for (let i = 0; i < length; ++i) { next[i] = trie[i]; } @@ -250,6 +252,7 @@ async function run$1(filePath, workerPath, maxWorkers, outPath = "") { tasks[i] = new Promise((resolve) => { worker.once("message", resolve); worker.postMessage({ + type: "process_request", counts, end, filePath, @@ -264,12 +267,33 @@ async function run$1(filePath, workerPath, maxWorkers, outPath = "") { for await (const res of tasks) { tries[res.id] = res.trie; } + for (let i = 0, j = maxWorkers - 1; i < j; i = 0) { + const merges = []; + for (; i < j; ++i) { + const a = i; + const b = j--; + const worker = workers[i]; + merges.push(new Promise((resolve) => { + worker.once("message", resolve); + worker.postMessage({ + type: "merge_request", + a, + b, + counts, + maxes, + mins, + sums, + tries + }); + })); + } + for await (const res of merges) { + tries[res.id] = res.trie; + } + } for (let i = 0; i < maxWorkers; ++i) { await workers[i].terminate(); } - for (let i = 1; i < maxWorkers; ++i) { - mergeLeft(tries, 0, i, mergeStations); - } const out = createWriteStream(outPath, { fd: outPath.length < 1 ? 1 : void 0, flags: "a", @@ -279,14 +303,6 @@ async function run$1(filePath, workerPath, maxWorkers, outPath = "") { out.write("{"); print(tries, buffer, 0, out, ", ", printStation); out.end("}\n"); - function mergeStations(ai, bi) { - ai <<= 3; - bi <<= 3; - mins[ai] = Math.min(mins[ai], mins[bi]); - maxes[ai] = Math.max(maxes[ai], maxes[bi]); - counts[ai >> 1] += counts[bi >> 1]; - sums[ai >> 2] += sums[bi >> 2]; - } function printStation(stream, name, nameLen, vi) { const avg = Math.round(sums[vi << 1] / counts[vi << 2]); stream.write(name.toString("utf8", 0, nameLen)); @@ -311,7 +327,7 @@ async function run({ sums }) { if (start >= end) { - return { id, trie: createTrie(id, 0) }; + return { type: "process_response", id, trie: createTrie(id, 0) }; } let trie = createTrie(id); let stations = id * MAX_STATIONS + 1; @@ -357,7 +373,7 @@ async function run({ ++counts[index >> 1]; sums[index >> 2] += temp; } - return { id, trie }; + return { type: "process_response", id, trie }; } function parseDouble(b, min, max) { if (b[min] === CHAR_MINUS) { @@ -366,14 +382,32 @@ function parseDouble(b, min, max) { } return min + 4 > max ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11 : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111; } +function merge({ a, b, tries, counts, maxes, mins, sums }) { + mergeLeft(tries, a, b, mergeStations); + function mergeStations(ai, bi) { + ai <<= 3; + bi <<= 3; + mins[ai] = Math.min(mins[ai], mins[bi]); + maxes[ai] = Math.max(maxes[ai], maxes[bi]); + counts[ai >> 1] += counts[bi >> 1]; + sums[ai >> 2] += sums[bi >> 2]; + } + return { type: "merge_response", id: a, trie: tries[a] }; +} if (isMainThread) { const workerPath = fileURLToPath(import.meta.url); run$1(process.argv[2], workerPath, availableParallelism()); } else { - parentPort.addListener("message", async (req) => { - const res = await run(req); - parentPort.postMessage(res, [res.trie.buffer]); + parentPort.addListener("message", async (msg) => { + if (msg.type === "process_request") { + const res = await run(msg); + parentPort.postMessage(res); + } + if (msg.type === "merge_request") { + const res = merge(msg); + parentPort.postMessage(res); + } }); } //# sourceMappingURL=index.mjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index 54d6727..cd6e948 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1 +1 @@ -{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN } from \"./utf8\";\n\n// Configurable constants\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 524288; // 2 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Internal trie pointer\n\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Cross-trie pointer (aka redirect)\n\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a null / undefined trie element.\n */\nexport const TRIE_NULL = 0;\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_PTR_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_XPTR_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach and initialize node\n trie[index + TRIE_PTR_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n const minSize = TRIE_MEM;\n const trie = new Int32Array(Math.max(minSize, size));\n trie[TRIE_SIZE_IDX] = minSize;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(minSize);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_PTR_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_PTR_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Add new redirect\n tries[at][li + TRIE_XPTR_ID_IDX] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_B0_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { mergeLeft, print } from \"./utils/utf8Trie\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n counts,\n end,\n filePath,\n id,\n maxes,\n mins,\n start,\n sums,\n } as WorkerRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n tries[res.id] = res.trie;\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Merge tries\n for (let i = 1; i < maxWorkers; ++i) {\n mergeLeft(tries, 0, i, mergeStations);\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\nimport type { WorkerResponse } from \"./types/workerResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: WorkerRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { WorkerRequest } from \"./types/workerRequest\";\n\nimport { run as runMain } from \"./main\";\nimport { run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (req: WorkerRequest) => {\n const res = await runWorker(req);\n parentPort!.postMessage(res, [res.trie.buffer]);\n });\n}\n"],"names":["at","bt","run","runMain","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN } from \"./utf8\";\n\n// Configurable constants\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 524288; // 2 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Internal trie pointer\n\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Cross-trie pointer (aka redirect)\n\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a null / undefined trie element.\n */\nexport const TRIE_NULL = 0;\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_PTR_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_XPTR_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach and initialize node\n trie[index + TRIE_PTR_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const buffer = new SharedArrayBuffer(size << 2);\n const trie = new Int32Array(buffer);\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const buffer = new SharedArrayBuffer(minSize << 2);\n const next = new Int32Array(buffer);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_PTR_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_PTR_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Add new redirect\n tries[at][li + TRIE_XPTR_ID_IDX] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_B0_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n type: \"process_request\",\n counts,\n end,\n filePath,\n id,\n maxes,\n mins,\n start,\n sums,\n } as ProcessRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n tries[res.id] = res.trie;\n }\n\n // Merge tries\n for (let i = 0, j = maxWorkers - 1; i < j; i = 0) {\n const merges: Promise[] = [];\n for (; i < j; ++i) {\n const a = i;\n const b = j--;\n const worker = workers[i];\n merges.push(new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n } as MergeRequest);\n }));\n }\n for await (const res of merges) {\n tries[res.id] = res.trie;\n }\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\nexport function merge({a, b, tries, counts, maxes, mins, sums}: MergeRequest): MergeResponse {\n mergeLeft(tries, a, b, mergeStations);\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n return { type: \"merge_response\", id: a, trie: tries[a] };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n const res = await runWorker(msg as ProcessRequest);\n parentPort!.postMessage(res);\n }\n if (msg.type === \"merge_request\") {\n const res = merge(msg as MergeRequest);\n parentPort!.postMessage(res);\n }\n });\n}\n"],"names":["at","bt","run","runMain","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/src/index.ts b/src/main/nodejs/havelessbemore/src/index.ts index 4f159cc..be64210 100644 --- a/src/main/nodejs/havelessbemore/src/index.ts +++ b/src/main/nodejs/havelessbemore/src/index.ts @@ -2,17 +2,24 @@ import { availableParallelism } from "node:os"; import { fileURLToPath } from "node:url"; import { isMainThread, parentPort } from "node:worker_threads"; -import type { WorkerRequest } from "./types/workerRequest"; - import { run as runMain } from "./main"; -import { run as runWorker } from "./worker"; +import { merge, run as runWorker } from "./worker"; +import { Message } from "./types/message"; +import { ProcessRequest } from "./types/processRequest"; +import { MergeRequest } from "./types/mergeRequest"; if (isMainThread) { const workerPath = fileURLToPath(import.meta.url); runMain(process.argv[2], workerPath, availableParallelism()); } else { - parentPort!.addListener("message", async (req: WorkerRequest) => { - const res = await runWorker(req); - parentPort!.postMessage(res, [res.trie.buffer]); + parentPort!.addListener("message", async (msg: Message) => { + if (msg.type === "process_request") { + const res = await runWorker(msg as ProcessRequest); + parentPort!.postMessage(res); + } + if (msg.type === "merge_request") { + const res = merge(msg as MergeRequest); + parentPort!.postMessage(res); + } }); } diff --git a/src/main/nodejs/havelessbemore/src/main.ts b/src/main/nodejs/havelessbemore/src/main.ts index 4d063e7..06732cb 100644 --- a/src/main/nodejs/havelessbemore/src/main.ts +++ b/src/main/nodejs/havelessbemore/src/main.ts @@ -1,8 +1,8 @@ import { WriteStream, createWriteStream } from "node:fs"; import { Worker } from "node:worker_threads"; -import type { WorkerRequest } from "./types/workerRequest"; -import type { WorkerResponse } from "./types/workerResponse"; +import type { ProcessRequest } from "./types/processRequest"; +import type { ProcessResponse } from "./types/processResponse"; import { ENTRY_MAX_LEN, @@ -12,7 +12,9 @@ import { import { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from "./constants/stream"; import { MAX_WORKERS, MIN_WORKERS } from "./constants/workers"; import { clamp, getFileChunks } from "./utils/stream"; -import { mergeLeft, print } from "./utils/utf8Trie"; +import { print } from "./utils/utf8Trie"; +import { MergeResponse } from "./types/mergeResponse"; +import { MergeRequest } from "./types/mergeRequest"; export async function run( filePath: string, @@ -61,7 +63,7 @@ export async function run( } // Process each chunk - const tasks = new Array>(maxWorkers); + const tasks = new Array>(maxWorkers); for (let i = 0; i < maxWorkers; ++i) { const id = i; const worker = workers[i]; @@ -69,6 +71,7 @@ export async function run( tasks[i] = new Promise((resolve) => { worker.once("message", resolve); worker.postMessage({ + type: "process_request", counts, end, filePath, @@ -77,7 +80,7 @@ export async function run( mins, start, sums, - } as WorkerRequest); + } as ProcessRequest); }); } @@ -86,16 +89,37 @@ export async function run( tries[res.id] = res.trie; } + // Merge tries + for (let i = 0, j = maxWorkers - 1; i < j; i = 0) { + const merges: Promise[] = []; + for (; i < j; ++i) { + const a = i; + const b = j--; + const worker = workers[i]; + merges.push(new Promise((resolve) => { + worker.once("message", resolve); + worker.postMessage({ + type: "merge_request", + a, + b, + counts, + maxes, + mins, + sums, + tries, + } as MergeRequest); + })); + } + for await (const res of merges) { + tries[res.id] = res.trie; + } + } + // Terminate workers for (let i = 0; i < maxWorkers; ++i) { await workers[i].terminate(); } - // Merge tries - for (let i = 1; i < maxWorkers; ++i) { - mergeLeft(tries, 0, i, mergeStations); - } - // Print results const out = createWriteStream(outPath, { fd: outPath.length < 1 ? 1 : undefined, @@ -107,15 +131,6 @@ export async function run( print(tries, buffer, 0, out, ", ", printStation); out.end("}\n"); - function mergeStations(ai: number, bi: number): void { - ai <<= 3; - bi <<= 3; - mins[ai] = Math.min(mins[ai], mins[bi]); - maxes[ai] = Math.max(maxes[ai], maxes[bi]); - counts[ai >> 1] += counts[bi >> 1]; - sums[ai >> 2] += sums[bi >> 2]; - } - function printStation( stream: WriteStream, name: Buffer, diff --git a/src/main/nodejs/havelessbemore/src/types/mergeRequest.ts b/src/main/nodejs/havelessbemore/src/types/mergeRequest.ts new file mode 100644 index 0000000..dfeda60 --- /dev/null +++ b/src/main/nodejs/havelessbemore/src/types/mergeRequest.ts @@ -0,0 +1,13 @@ +import { Message } from "./message"; + +export interface MergeRequest extends Message { + type: "merge_request"; + a: number; + b: number; + // Shared memory + counts: Uint32Array; + maxes: Int16Array; + mins: Int16Array; + sums: Float64Array; + tries: Int32Array[]; +} diff --git a/src/main/nodejs/havelessbemore/src/types/mergeResponse.ts b/src/main/nodejs/havelessbemore/src/types/mergeResponse.ts new file mode 100644 index 0000000..756a958 --- /dev/null +++ b/src/main/nodejs/havelessbemore/src/types/mergeResponse.ts @@ -0,0 +1,7 @@ +import { Message } from "./message"; + +export interface MergeResponse extends Message { + type: "merge_response"; + id: number; + trie: Int32Array; +} diff --git a/src/main/nodejs/havelessbemore/src/types/message.ts b/src/main/nodejs/havelessbemore/src/types/message.ts new file mode 100644 index 0000000..6a33e4c --- /dev/null +++ b/src/main/nodejs/havelessbemore/src/types/message.ts @@ -0,0 +1,4 @@ +export interface Message { + type: string; +} + \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/src/types/workerRequest.ts b/src/main/nodejs/havelessbemore/src/types/processRequest.ts similarity index 60% rename from src/main/nodejs/havelessbemore/src/types/workerRequest.ts rename to src/main/nodejs/havelessbemore/src/types/processRequest.ts index 88909f9..eb6c4cd 100644 --- a/src/main/nodejs/havelessbemore/src/types/workerRequest.ts +++ b/src/main/nodejs/havelessbemore/src/types/processRequest.ts @@ -1,4 +1,7 @@ -export interface WorkerRequest { +import { Message } from "./message"; + +export interface ProcessRequest extends Message { + type: "process_request"; end: number; filePath: string; id: number; diff --git a/src/main/nodejs/havelessbemore/src/types/processResponse.ts b/src/main/nodejs/havelessbemore/src/types/processResponse.ts new file mode 100644 index 0000000..c12c521 --- /dev/null +++ b/src/main/nodejs/havelessbemore/src/types/processResponse.ts @@ -0,0 +1,7 @@ +import { Message } from "./message"; + +export interface ProcessResponse extends Message { + type: "process_response"; + id: number; + trie: Int32Array; +} diff --git a/src/main/nodejs/havelessbemore/src/types/workerResponse.ts b/src/main/nodejs/havelessbemore/src/types/workerResponse.ts deleted file mode 100644 index 42f8c1f..0000000 --- a/src/main/nodejs/havelessbemore/src/types/workerResponse.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface WorkerResponse { - id: number; - trie: Int32Array; -} diff --git a/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts b/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts index cf36e04..cf4d3c2 100644 --- a/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts +++ b/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts @@ -50,9 +50,9 @@ export function add( } export function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array { - const minSize = TRIE_MEM; - const trie = new Int32Array(Math.max(minSize, size)); - trie[TRIE_SIZE_IDX] = minSize; + size = Math.max(TRIE_MEM, size); + const trie = new Int32Array(new SharedArrayBuffer(size << 2)); + trie[TRIE_SIZE_IDX] = TRIE_MEM; trie[TRIE_ID_IDX] = id; return trie; } @@ -60,7 +60,7 @@ export function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array { export function grow(trie: Int32Array, minSize = 0): Int32Array { const length = trie[TRIE_SIZE_IDX]; minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR)); - const next = new Int32Array(minSize); + const next = new Int32Array(new SharedArrayBuffer(minSize << 2)); for (let i = 0; i < length; ++i) { next[i] = trie[i]; } diff --git a/src/main/nodejs/havelessbemore/src/worker.ts b/src/main/nodejs/havelessbemore/src/worker.ts index 5f8f367..73bac57 100644 --- a/src/main/nodejs/havelessbemore/src/worker.ts +++ b/src/main/nodejs/havelessbemore/src/worker.ts @@ -1,7 +1,7 @@ import { createReadStream } from "node:fs"; -import type { WorkerRequest } from "./types/workerRequest"; -import type { WorkerResponse } from "./types/workerResponse"; +import type { ProcessRequest } from "./types/processRequest"; +import type { ProcessResponse } from "./types/processResponse"; import { CHAR_SEMICOLON } from "./constants/utf8"; import { CHAR_NEWLINE } from "./constants/utf8"; @@ -10,7 +10,9 @@ import { ENTRY_MAX_LEN, MAX_STATIONS } from "./constants/constraints"; import { CHAR_ZERO_11, CHAR_ZERO_111 } from "./constants/stream"; import { TRIE_NODE_VALUE_IDX, TRIE_NULL } from "./constants/utf8Trie"; import { getHighWaterMark } from "./utils/stream"; -import { add, createTrie } from "./utils/utf8Trie"; +import { add, createTrie, mergeLeft } from "./utils/utf8Trie"; +import { MergeRequest } from "./types/mergeRequest"; +import { MergeResponse } from "./types/mergeResponse"; export async function run({ end, @@ -22,10 +24,10 @@ export async function run({ maxes, mins, sums, -}: WorkerRequest): Promise { +}: ProcessRequest): Promise { // Check chunk size if (start >= end) { - return { id, trie: createTrie(id, 0) }; + return { type: "process_response", id, trie: createTrie(id, 0) }; } // Initialize constants @@ -88,7 +90,7 @@ export async function run({ sums[index >> 2] += temp; } - return { id, trie }; + return { type: "process_response", id, trie }; } export function parseDouble(b: Buffer, min: number, max: number): number { @@ -102,3 +104,16 @@ export function parseDouble(b: Buffer, min: number, max: number): number { ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11 : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111; } + +export function merge({a, b, tries, counts, maxes, mins, sums}: MergeRequest): MergeResponse { + mergeLeft(tries, a, b, mergeStations); + function mergeStations(ai: number, bi: number): void { + ai <<= 3; + bi <<= 3; + mins[ai] = Math.min(mins[ai], mins[bi]); + maxes[ai] = Math.max(maxes[ai], maxes[bi]); + counts[ai >> 1] += counts[bi >> 1]; + sums[ai >> 2] += sums[bi >> 2]; + } + return { type: "merge_response", id: a, trie: tries[a] }; +} From e7d8f0fdd49b1a587edd441ca21a606b3a39225b Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Thu, 23 May 2024 10:29:17 -0400 Subject: [PATCH 15/69] Minify output --- src/main/nodejs/havelessbemore/rollup.config.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/nodejs/havelessbemore/rollup.config.ts b/src/main/nodejs/havelessbemore/rollup.config.ts index 31a6cc5..bbc7b9c 100644 --- a/src/main/nodejs/havelessbemore/rollup.config.ts +++ b/src/main/nodejs/havelessbemore/rollup.config.ts @@ -13,7 +13,12 @@ function bundle(config: RollupOptions): RollupOptions { export default [ bundle({ - plugins: [esbuild({ target: "ES2022" })], + plugins: [ + esbuild({ + target: "ES2022", + minify: true, + }), + ], output: [ { file: pkg.main, From 3e83ee79683e82befc56ff21bea8d7d396ab1d46 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Thu, 23 May 2024 10:29:38 -0400 Subject: [PATCH 16/69] Update best time in README.md --- src/main/nodejs/havelessbemore/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/nodejs/havelessbemore/README.md b/src/main/nodejs/havelessbemore/README.md index 040bb77..a3545f4 100644 --- a/src/main/nodejs/havelessbemore/README.md +++ b/src/main/nodejs/havelessbemore/README.md @@ -15,7 +15,7 @@ ### Results - Min: 14.5s -- Avg: 15.4s +- Avg: 15s ### Specs: From 54c0d04960dd005681b26850c5dc6a510366063b Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Thu, 23 May 2024 10:30:20 -0400 Subject: [PATCH 17/69] Add utility functions for working with Workers --- .../nodejs/havelessbemore/src/utils/worker.ts | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 src/main/nodejs/havelessbemore/src/utils/worker.ts diff --git a/src/main/nodejs/havelessbemore/src/utils/worker.ts b/src/main/nodejs/havelessbemore/src/utils/worker.ts new file mode 100644 index 0000000..2afce03 --- /dev/null +++ b/src/main/nodejs/havelessbemore/src/utils/worker.ts @@ -0,0 +1,39 @@ +import { Worker } from "worker_threads"; + +/** + * Creates a new Worker instance. + * + * @param workerPath - The path to the worker script. + * + * @returns A new Worker instance. + */ +export function createWorker(workerPath: string): Worker { + const worker = new Worker(workerPath); + worker.on("error", (err) => { + throw err; + }); + worker.on("messageerror", (err) => { + throw err; + }); + worker.on("exit", (code) => { + if (code > 1 || code < 0) { + throw new Error(`Worker ${worker.threadId} exited with code ${code}`); + } + }); + return worker; +} + +/** + * Executes a task on a Worker and returns a Promise that resolves with the response. + * + * @param worker - The Worker instance to execute the task. + * @param req - The request to send to the worker. + * + * @returns A Promise that resolves with the response from the worker. + */ +export function exec(worker: Worker, req: Req): Promise { + return new Promise((resolve) => { + worker.once("message", resolve); + worker.postMessage(req); + }); +} From 6402106c9eaf7441531c293c78103d2e5972e61e Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Thu, 23 May 2024 10:31:31 -0400 Subject: [PATCH 18/69] Format files --- src/main/nodejs/havelessbemore/src/types/message.ts | 3 +-- src/main/nodejs/havelessbemore/src/worker.ts | 10 +++++++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/main/nodejs/havelessbemore/src/types/message.ts b/src/main/nodejs/havelessbemore/src/types/message.ts index 6a33e4c..687654b 100644 --- a/src/main/nodejs/havelessbemore/src/types/message.ts +++ b/src/main/nodejs/havelessbemore/src/types/message.ts @@ -1,4 +1,3 @@ export interface Message { - type: string; + type: string; } - \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/src/worker.ts b/src/main/nodejs/havelessbemore/src/worker.ts index 73bac57..127ba32 100644 --- a/src/main/nodejs/havelessbemore/src/worker.ts +++ b/src/main/nodejs/havelessbemore/src/worker.ts @@ -105,7 +105,15 @@ export function parseDouble(b: Buffer, min: number, max: number): number { : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111; } -export function merge({a, b, tries, counts, maxes, mins, sums}: MergeRequest): MergeResponse { +export function merge({ + a, + b, + tries, + counts, + maxes, + mins, + sums, +}: MergeRequest): MergeResponse { mergeLeft(tries, a, b, mergeStations); function mergeStations(ai: number, bi: number): void { ai <<= 3; From 9819a4fe947b48a7ee08e91da726add57344c7dc Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Thu, 23 May 2024 10:32:37 -0400 Subject: [PATCH 19/69] Refactor worker message listener --- src/main/nodejs/havelessbemore/src/index.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/nodejs/havelessbemore/src/index.ts b/src/main/nodejs/havelessbemore/src/index.ts index be64210..bfefe81 100644 --- a/src/main/nodejs/havelessbemore/src/index.ts +++ b/src/main/nodejs/havelessbemore/src/index.ts @@ -16,10 +16,11 @@ if (isMainThread) { if (msg.type === "process_request") { const res = await runWorker(msg as ProcessRequest); parentPort!.postMessage(res); - } - if (msg.type === "merge_request") { + } else if (msg.type === "merge_request") { const res = merge(msg as MergeRequest); parentPort!.postMessage(res); + } else { + throw new Error("Unknown message type"); } }); } From 6026a8fff46061b9f89d480b456b339febcd6c11 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Thu, 23 May 2024 10:34:20 -0400 Subject: [PATCH 20/69] Refactor main --- src/main/nodejs/havelessbemore/dist/index.cjs | 417 +----------------- .../nodejs/havelessbemore/dist/index.cjs.map | 2 +- src/main/nodejs/havelessbemore/dist/index.mjs | 414 +---------------- .../nodejs/havelessbemore/dist/index.mjs.map | 2 +- src/main/nodejs/havelessbemore/src/main.ts | 82 ++-- 5 files changed, 37 insertions(+), 880 deletions(-) diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs b/src/main/nodejs/havelessbemore/dist/index.cjs index c0ca613..1dd4348 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs +++ b/src/main/nodejs/havelessbemore/dist/index.cjs @@ -1,416 +1,3 @@ -'use strict'; - -var node_os = require('node:os'); -var node_url = require('node:url'); -var node_worker_threads = require('node:worker_threads'); -var node_fs = require('node:fs'); -var promises = require('fs/promises'); - -var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null; -const MAX_STATIONS = 1e4; -const STATION_NAME_MAX_LEN = 100; -const ENTRY_MAX_LEN = 107; - -const CHAR_MINUS = 45; -const CHAR_NEWLINE = 10; -const CHAR_SEMICOLON = 59; -const CHAR_ZERO = 48; -const UTF8_B0_MIN = 32; -const UTF8_B0_2B_MAX = 223; -const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1; - -const HIGH_WATER_MARK_MIN = 16384; -const HIGH_WATER_MARK_MAX = 1048576; -const HIGH_WATER_MARK_OUT = 1048576; -const HIGH_WATER_MARK_RATIO = 152e-6; -const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN; -const CHAR_ZERO_11 = 11 * CHAR_ZERO; -const CHAR_ZERO_111 = 111 * CHAR_ZERO; - -const MIN_WORKERS = 1; -const MAX_WORKERS = 512; - -function clamp(value, min, max) { - return value > min ? value <= max ? value : max : min; -} -async function getFileChunks(filePath, target, maxLineLength, minSize = 0) { - const file = await promises.open(filePath); - try { - const size = (await file.stat()).size; - const chunkSize = Math.max(minSize, Math.floor(size / target)); - const buffer = Buffer.allocUnsafe(maxLineLength); - const chunks = []; - let start = 0; - for (let end = chunkSize; end < size; end += chunkSize) { - const res = await file.read(buffer, 0, maxLineLength, end); - const newline = buffer.indexOf(CHAR_NEWLINE); - if (newline >= 0 && newline < res.bytesRead) { - end += newline + 1; - chunks.push([start, end]); - start = end; - } - } - if (start < size) { - chunks.push([start, size]); - } - return chunks; - } finally { - await file.close(); - } -} -function getHighWaterMark(size) { - size *= HIGH_WATER_MARK_RATIO; - size = Math.round(Math.log2(size)); - size = 2 ** size; - return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX); -} - -const TRIE_DEFAULT_SIZE = 524288; -const TRIE_GROWTH_FACTOR = 1.6180339887; -const TRIE_PTR_IDX_IDX = 0; -const TRIE_PTR_IDX_MEM = 1; -const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM; -const TRIE_XPTR_ID_IDX = 0; -const TRIE_XPTR_ID_MEM = 1; -const TRIE_XPTR_IDX_IDX = 1; -const TRIE_XPTR_IDX_MEM = 1; -const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM; -const TRIE_NODE_ID_IDX = 0; -const TRIE_NODE_ID_MEM = 1; -const TRIE_NODE_VALUE_IDX = 1; -const TRIE_NODE_VALUE_MEM = 1; -const TRIE_NODE_CHILDREN_IDX = 2; -const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN; -const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN; -const TRIE_NODE_MEM = TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM; -const TRIE_NULL = 0; -const TRIE_SIZE_IDX = 0; -const TRIE_SIZE_MEM = 1; -const TRIE_ROOT_IDX = 1; -const TRIE_ROOT_MEM = TRIE_NODE_MEM; -const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX; -const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM; - -function add(trie, key, min, max) { - let index = TRIE_ROOT_IDX; - while (min < max) { - index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN); - let child = trie[index + TRIE_PTR_IDX_IDX]; - if (child === TRIE_NULL) { - child = trie[TRIE_SIZE_IDX]; - if (child + TRIE_NODE_MEM > trie.length) { - trie = grow(trie, child + TRIE_NODE_MEM); - } - trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM; - trie[index + TRIE_PTR_IDX_IDX] = child; - trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX]; - } - index = child; - } - return [trie, index]; -} -function createTrie(id = 0, size = TRIE_DEFAULT_SIZE) { - size = Math.max(TRIE_MEM, size); - const buffer = new SharedArrayBuffer(size << 2); - const trie = new Int32Array(buffer); - trie[TRIE_SIZE_IDX] = TRIE_MEM; - trie[TRIE_ID_IDX] = id; - return trie; -} -function grow(trie, minSize = 0) { - const length = trie[TRIE_SIZE_IDX]; - minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR)); - const buffer = new SharedArrayBuffer(minSize << 2); - const next = new Int32Array(buffer); - for (let i = 0; i < length; ++i) { - next[i] = trie[i]; - } - return next; -} -function mergeLeft(tries, at, bt, mergeFn) { - const queue = [ - [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX] - ]; - do { - const Q = queue.length; - for (let q = 0; q < Q; ++q) { - let [at2, ai, bt2, bi] = queue[q]; - const bvi = tries[bt2][bi + TRIE_NODE_VALUE_IDX]; - if (bvi !== TRIE_NULL) { - const avi = tries[at2][ai + TRIE_NODE_VALUE_IDX]; - if (avi !== TRIE_NULL) { - mergeFn(avi, bvi); - } else { - tries[at2][ai + TRIE_NODE_VALUE_IDX] = bvi; - } - } - ai += TRIE_NODE_CHILDREN_IDX; - bi += TRIE_NODE_CHILDREN_IDX; - const bn = bi + TRIE_NODE_CHILDREN_MEM; - while (bi < bn) { - let ri = tries[bt2][bi + TRIE_PTR_IDX_IDX]; - if (ri === TRIE_NULL) { - ai += TRIE_PTR_MEM; - bi += TRIE_PTR_MEM; - continue; - } - const rt = tries[bt2][ri + TRIE_NODE_ID_IDX]; - if (bt2 !== rt) { - ri = tries[bt2][ri + TRIE_XPTR_IDX_IDX]; - } - let li = tries[at2][ai + TRIE_PTR_IDX_IDX]; - if (li === TRIE_NULL) { - li = tries[at2][TRIE_SIZE_IDX]; - if (li + TRIE_XPTR_MEM > tries[at2].length) { - tries[at2] = grow(tries[at2], li + TRIE_XPTR_MEM); - } - tries[at2][TRIE_SIZE_IDX] += TRIE_XPTR_MEM; - tries[at2][li + TRIE_XPTR_ID_IDX] = rt; - tries[at2][li + TRIE_XPTR_IDX_IDX] = ri; - } else { - const lt = tries[at2][li + TRIE_NODE_ID_IDX]; - if (at2 !== lt) { - ai = tries[at2][li + TRIE_XPTR_IDX_IDX]; - } - queue.push([lt, li, rt, ri]); - } - ai += TRIE_PTR_MEM; - bi += TRIE_PTR_MEM; - } - } - queue.splice(0, Q); - } while (queue.length > 0); -} -function print(tries, key, trieIndex, stream, separator = "", callbackFn) { - const stack = new Array(key.length + 1); - stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0]; - let top = 0; - let tail = false; - do { - let [trieI, childPtr, numChild] = stack[top]; - if (numChild >= TRIE_NODE_CHILDREN_LEN) { - --top; - continue; - } - stack[top][1] += TRIE_PTR_MEM; - ++stack[top][2]; - let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX]; - if (childI === TRIE_NULL) { - continue; - } - const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX]; - if (trieI !== childTrieI) { - childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX]; - trieI = childTrieI; - } - key[top] = numChild + UTF8_B0_MIN; - stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0]; - const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX]; - if (valueIndex !== TRIE_NULL) { - if (tail) { - stream.write(separator); - } - tail = true; - callbackFn(stream, key, top, valueIndex); - } - } while (top >= 0); -} - -async function run$1(filePath, workerPath, maxWorkers, outPath = "") { - maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS); - const chunks = await getFileChunks( - filePath, - maxWorkers, - ENTRY_MAX_LEN, - CHUNK_SIZE_MIN - ); - maxWorkers = chunks.length; - const valBuf = new SharedArrayBuffer(MAX_STATIONS * maxWorkers + 1 << 4); - const mins = new Int16Array(valBuf); - const maxes = new Int16Array(valBuf, 2); - const counts = new Uint32Array(valBuf, 4); - const sums = new Float64Array(valBuf, 8); - const tries = new Array(maxWorkers); - const workers = new Array(maxWorkers); - for (let i = 0; i < maxWorkers; ++i) { - const worker = new node_worker_threads.Worker(workerPath); - worker.on("error", (err) => { - throw err; - }); - worker.on("messageerror", (err) => { - throw err; - }); - worker.on("exit", (code) => { - if (code > 1 || code < 0) { - throw new Error(`Worker ${worker.threadId} exited with code ${code}`); - } - }); - workers[i] = worker; - } - const tasks = new Array(maxWorkers); - for (let i = 0; i < maxWorkers; ++i) { - const id = i; - const worker = workers[i]; - const [start, end] = chunks[i]; - tasks[i] = new Promise((resolve) => { - worker.once("message", resolve); - worker.postMessage({ - type: "process_request", - counts, - end, - filePath, - id, - maxes, - mins, - start, - sums - }); - }); - } - for await (const res of tasks) { - tries[res.id] = res.trie; - } - for (let i = 0, j = maxWorkers - 1; i < j; i = 0) { - const merges = []; - for (; i < j; ++i) { - const a = i; - const b = j--; - const worker = workers[i]; - merges.push(new Promise((resolve) => { - worker.once("message", resolve); - worker.postMessage({ - type: "merge_request", - a, - b, - counts, - maxes, - mins, - sums, - tries - }); - })); - } - for await (const res of merges) { - tries[res.id] = res.trie; - } - } - for (let i = 0; i < maxWorkers; ++i) { - await workers[i].terminate(); - } - const out = node_fs.createWriteStream(outPath, { - fd: outPath.length < 1 ? 1 : void 0, - flags: "a", - highWaterMark: HIGH_WATER_MARK_OUT - }); - const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN); - out.write("{"); - print(tries, buffer, 0, out, ", ", printStation); - out.end("}\n"); - function printStation(stream, name, nameLen, vi) { - const avg = Math.round(sums[vi << 1] / counts[vi << 2]); - stream.write(name.toString("utf8", 0, nameLen)); - stream.write("="); - stream.write((mins[vi << 3] / 10).toFixed(1)); - stream.write("/"); - stream.write((avg / 10).toFixed(1)); - stream.write("/"); - stream.write((maxes[vi << 3] / 10).toFixed(1)); - } -} - -async function run({ - end, - filePath, - id, - start, - // Shared memory - counts, - maxes, - mins, - sums -}) { - if (start >= end) { - return { type: "process_response", id, trie: createTrie(id, 0) }; - } - let trie = createTrie(id); - let stations = id * MAX_STATIONS + 1; - const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN); - const stream = node_fs.createReadStream(filePath, { - start, - end: end - 1, - highWaterMark: getHighWaterMark(end - start) - }); - let bufI = 0; - let tempI = 0; - let leaf; - for await (const chunk of stream) { - const N = chunk.length; - for (let i = 0; i < N; ++i) { - if (chunk[i] === CHAR_SEMICOLON) { - tempI = bufI; - } else if (chunk[i] !== CHAR_NEWLINE) { - buffer[bufI++] = chunk[i]; - } else { - const tempV = parseDouble(buffer, tempI, bufI); - bufI = 0; - [trie, leaf] = add(trie, buffer, 0, tempI); - if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) { - updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV); - } else { - trie[leaf + TRIE_NODE_VALUE_IDX] = stations; - newStation(stations++, tempV); - } - } - } - } - function newStation(index, temp) { - mins[index << 3] = temp; - maxes[index << 3] = temp; - counts[index << 2] = 1; - sums[index << 1] = temp; - } - function updateStation(index, temp) { - index <<= 3; - mins[index] = mins[index] <= temp ? mins[index] : temp; - maxes[index] = maxes[index] >= temp ? maxes[index] : temp; - ++counts[index >> 1]; - sums[index >> 2] += temp; - } - return { type: "process_response", id, trie }; -} -function parseDouble(b, min, max) { - if (b[min] === CHAR_MINUS) { - ++min; - return min + 4 > max ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11) : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111); - } - return min + 4 > max ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11 : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111; -} -function merge({ a, b, tries, counts, maxes, mins, sums }) { - mergeLeft(tries, a, b, mergeStations); - function mergeStations(ai, bi) { - ai <<= 3; - bi <<= 3; - mins[ai] = Math.min(mins[ai], mins[bi]); - maxes[ai] = Math.max(maxes[ai], maxes[bi]); - counts[ai >> 1] += counts[bi >> 1]; - sums[ai >> 2] += sums[bi >> 2]; - } - return { type: "merge_response", id: a, trie: tries[a] }; -} - -if (node_worker_threads.isMainThread) { - const workerPath = node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href))); - run$1(process.argv[2], workerPath, node_os.availableParallelism()); -} else { - node_worker_threads.parentPort.addListener("message", async (msg) => { - if (msg.type === "process_request") { - const res = await run(msg); - node_worker_threads.parentPort.postMessage(res); - } - if (msg.type === "merge_request") { - const res = merge(msg); - node_worker_threads.parentPort.postMessage(res); - } - }); -} +"use strict";var Y=require("node:os"),J=require("node:url"),X=require("node:worker_threads"),U=require("node:fs"),Q=require("fs/promises"),ee=require("worker_threads"),P=typeof document<"u"?document.currentScript:null;const x=1e4,te=100,W=107,re=45,C=10,ne=59,q=48,k=32,se=192,v=16384,ae=1048576,oe=1048576,ie=152e-6,_e=v,F=11*q,B=111*q,ce=1,ue=512;function b(e,t,r){return e>t?e<=r?e:r:t}async function Ee(e,t,r,l=0){const a=await Q.open(e);try{const i=(await a.stat()).size,f=Math.max(l,Math.floor(i/t)),s=Buffer.allocUnsafe(r),o=[];let _=0;for(let E=f;E=0&&ue.length&&(e=j(e,i+L)),e[g]+=L,e[a+p]=i,e[i+D]=e[G]),a=i}return[e,a]}function V(e=0,t=le){t=Math.max($,t);const r=new Int32Array(new SharedArrayBuffer(t<<2));return r[g]=$,r[G]=e,r}function j(e,t=0){const r=e[g];t=Math.max(t,Math.ceil(r*Ie));const l=new Int32Array(new SharedArrayBuffer(t<<2));for(let a=0;ae[s].length&&(e[s]=j(e[s],h+S)),e[s][g]+=S,e[s][h+Me]=T,e[s][h+H]=I;else{const n=e[s][h+D];s!==n&&(o=e[s][h+H]),a.push([n,h,T,I])}o+=m,E+=m}}a.splice(0,i)}while(a.length>0)}function De(e,t,r,l,a="",i){const f=new Array(t.length+1);f[0]=[r,N+y,0];let s=0,o=!1;do{let[_,E,M]=f[s];if(M>=K){--s;continue}f[s][1]+=m,++f[s][2];let u=e[_][E+p];if(u===w)continue;const I=e[_][u+D];_!==I&&(u=e[_][u+H],_=I),t[s]=M+k,f[++s]=[_,u+y,0];const T=e[_][u+A];T!==w&&(o&&l.write(a),o=!0,i(l,t,s,T))}while(s>=0)}function ye(e){const t=new ee.Worker(e);return t.on("error",r=>{throw r}),t.on("messageerror",r=>{throw r}),t.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${t.threadId} exited with code ${r}`)}),t}function z(e,t){return new Promise(r=>{e.once("message",r),e.postMessage(t)})}async function Ne(e,t,r,l=""){r=b(r,ce,ue);const a=await Ee(e,r,W,_e);r=a.length;const i=new SharedArrayBuffer(x*r+1<<4),f=new Int16Array(i),s=new Int16Array(i,2),o=new Uint32Array(i,4),_=new Float64Array(i,8),E=new Array(r),M=new Array(r);for(let n=0;n{E[c.id]=c.trie});for(let n=u.length-1;n>0;--n){const c=n-1>>1,R=n;u[c]=u[c].then(()=>u[R]).then(()=>z(M[c],{type:"merge_request",a:c,b:R,counts:o,maxes:s,mins:f,sums:_,tries:E})).then(d=>{E[d.id]=d.trie})}for(let n=0;nM[n].terminate());await Promise.all(u);const I=U.createWriteStream(l,{fd:l.length<1?1:void 0,flags:"a",highWaterMark:oe}),T=Buffer.allocUnsafe(te);I.write("{"),De(E,T,0,I,", ",h),I.end(`} +`);function h(n,c,R,d){const O=Math.round(_[d<<1]/o[d<<2]);n.write(c.toString("utf8",0,R)),n.write("="),n.write((f[d<<3]/10).toFixed(1)),n.write("/"),n.write((O/10).toFixed(1)),n.write("/"),n.write((s[d<<3]/10).toFixed(1))}}async function Oe({end:e,filePath:t,id:r,start:l,counts:a,maxes:i,mins:f,sums:s}){if(l>=e)return{type:"process_response",id:r,trie:V(r,0)};let o=V(r),_=r*x+1;const E=Buffer.allocUnsafe(W),M=U.createReadStream(t,{start:l,end:e-1,highWaterMark:fe(e-l)});let u=0,I=0,T;for await(const c of M){const R=c.length;for(let d=0;d=R?i[c]:R,++a[c>>1],s[c>>2]+=R}return{type:"process_response",id:r,trie:o}}function Xe(e,t,r){return e[t]===re?(++t,t+4>r?-(10*e[t]+e[t+2]-F):-(100*e[t]+10*e[t+1]+e[t+3]-B)):t+4>r?10*e[t]+e[t+2]-F:100*e[t]+10*e[t+1]+e[t+3]-B}function He({a:e,b:t,tries:r,counts:l,maxes:a,mins:i,sums:f}){pe(r,e,t,s);function s(o,_){o<<=3,_<<=3,i[o]=Math.min(i[o],i[_]),a[o]=Math.max(a[o],a[_]),l[o>>1]+=l[_>>1],f[o>>2]+=f[_>>2]}return{type:"merge_response",id:e,trie:r[e]}}if(X.isMainThread){const e=J.fileURLToPath(typeof document>"u"?require("url").pathToFileURL(__filename).href:P&&P.src||new URL("index.cjs",document.baseURI).href);Ne(process.argv[2],e,Y.availableParallelism())}else X.parentPort.addListener("message",async e=>{if(e.type==="process_request"){const t=await Oe(e);X.parentPort.postMessage(t)}else if(e.type==="merge_request"){const t=He(e);X.parentPort.postMessage(t)}else throw new Error("Unknown message type")}); //# sourceMappingURL=index.cjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs.map b/src/main/nodejs/havelessbemore/dist/index.cjs.map index dc8ed48..be01de4 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.cjs.map @@ -1 +1 @@ -{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN } from \"./utf8\";\n\n// Configurable constants\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 524288; // 2 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Internal trie pointer\n\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Cross-trie pointer (aka redirect)\n\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a null / undefined trie element.\n */\nexport const TRIE_NULL = 0;\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_PTR_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_XPTR_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach and initialize node\n trie[index + TRIE_PTR_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const buffer = new SharedArrayBuffer(size << 2);\n const trie = new Int32Array(buffer);\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const buffer = new SharedArrayBuffer(minSize << 2);\n const next = new Int32Array(buffer);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_PTR_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_PTR_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Add new redirect\n tries[at][li + TRIE_XPTR_ID_IDX] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_B0_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n type: \"process_request\",\n counts,\n end,\n filePath,\n id,\n maxes,\n mins,\n start,\n sums,\n } as ProcessRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n tries[res.id] = res.trie;\n }\n\n // Merge tries\n for (let i = 0, j = maxWorkers - 1; i < j; i = 0) {\n const merges: Promise[] = [];\n for (; i < j; ++i) {\n const a = i;\n const b = j--;\n const worker = workers[i];\n merges.push(new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n } as MergeRequest);\n }));\n }\n for await (const res of merges) {\n tries[res.id] = res.trie;\n }\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\nexport function merge({a, b, tries, counts, maxes, mins, sums}: MergeRequest): MergeResponse {\n mergeLeft(tries, a, b, mergeStations);\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n return { type: \"merge_response\", id: a, trie: tries[a] };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n const res = await runWorker(msg as ProcessRequest);\n parentPort!.postMessage(res);\n }\n if (msg.type === \"merge_request\") {\n const res = merge(msg as MergeRequest);\n parentPort!.postMessage(res);\n }\n });\n}\n"],"names":["open","at","bt","run","Worker","createWriteStream","createReadStream","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN } from \"./utf8\";\n\n// Configurable constants\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 524288; // 2 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Internal trie pointer\n\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Cross-trie pointer (aka redirect)\n\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a null / undefined trie element.\n */\nexport const TRIE_NULL = 0;\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_PTR_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_XPTR_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach and initialize node\n trie[index + TRIE_PTR_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_PTR_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_PTR_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Add new redirect\n tries[at][li + TRIE_XPTR_ID_IDX] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_B0_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n mergeLeft(tries, a, b, mergeStations);\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n return { type: \"merge_response\", id: a, trie: tries[a] };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n const res = await runWorker(msg as ProcessRequest);\n parentPort!.postMessage(res);\n } else if (msg.type === \"merge_request\") {\n const res = merge(msg as MergeRequest);\n parentPort!.postMessage(res);\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_B0_MIN","UTF8_B0_2B_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","CHAR_ZERO_11","CHAR_ZERO_111","MIN_WORKERS","MAX_WORKERS","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_IDX","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_IDX","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","stations","createReadStream","bufI","tempI","leaf","chunk","N","tempV","parseDouble","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","_documentCurrentScript","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index 9e2d2df..0c8111e 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -1,413 +1,3 @@ -import { availableParallelism } from 'node:os'; -import { fileURLToPath } from 'node:url'; -import { Worker, isMainThread, parentPort } from 'node:worker_threads'; -import { createWriteStream, createReadStream } from 'node:fs'; -import { open } from 'fs/promises'; - -const MAX_STATIONS = 1e4; -const STATION_NAME_MAX_LEN = 100; -const ENTRY_MAX_LEN = 107; - -const CHAR_MINUS = 45; -const CHAR_NEWLINE = 10; -const CHAR_SEMICOLON = 59; -const CHAR_ZERO = 48; -const UTF8_B0_MIN = 32; -const UTF8_B0_2B_MAX = 223; -const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1; - -const HIGH_WATER_MARK_MIN = 16384; -const HIGH_WATER_MARK_MAX = 1048576; -const HIGH_WATER_MARK_OUT = 1048576; -const HIGH_WATER_MARK_RATIO = 152e-6; -const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN; -const CHAR_ZERO_11 = 11 * CHAR_ZERO; -const CHAR_ZERO_111 = 111 * CHAR_ZERO; - -const MIN_WORKERS = 1; -const MAX_WORKERS = 512; - -function clamp(value, min, max) { - return value > min ? value <= max ? value : max : min; -} -async function getFileChunks(filePath, target, maxLineLength, minSize = 0) { - const file = await open(filePath); - try { - const size = (await file.stat()).size; - const chunkSize = Math.max(minSize, Math.floor(size / target)); - const buffer = Buffer.allocUnsafe(maxLineLength); - const chunks = []; - let start = 0; - for (let end = chunkSize; end < size; end += chunkSize) { - const res = await file.read(buffer, 0, maxLineLength, end); - const newline = buffer.indexOf(CHAR_NEWLINE); - if (newline >= 0 && newline < res.bytesRead) { - end += newline + 1; - chunks.push([start, end]); - start = end; - } - } - if (start < size) { - chunks.push([start, size]); - } - return chunks; - } finally { - await file.close(); - } -} -function getHighWaterMark(size) { - size *= HIGH_WATER_MARK_RATIO; - size = Math.round(Math.log2(size)); - size = 2 ** size; - return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX); -} - -const TRIE_DEFAULT_SIZE = 524288; -const TRIE_GROWTH_FACTOR = 1.6180339887; -const TRIE_PTR_IDX_IDX = 0; -const TRIE_PTR_IDX_MEM = 1; -const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM; -const TRIE_XPTR_ID_IDX = 0; -const TRIE_XPTR_ID_MEM = 1; -const TRIE_XPTR_IDX_IDX = 1; -const TRIE_XPTR_IDX_MEM = 1; -const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM; -const TRIE_NODE_ID_IDX = 0; -const TRIE_NODE_ID_MEM = 1; -const TRIE_NODE_VALUE_IDX = 1; -const TRIE_NODE_VALUE_MEM = 1; -const TRIE_NODE_CHILDREN_IDX = 2; -const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN; -const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN; -const TRIE_NODE_MEM = TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM; -const TRIE_NULL = 0; -const TRIE_SIZE_IDX = 0; -const TRIE_SIZE_MEM = 1; -const TRIE_ROOT_IDX = 1; -const TRIE_ROOT_MEM = TRIE_NODE_MEM; -const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX; -const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM; - -function add(trie, key, min, max) { - let index = TRIE_ROOT_IDX; - while (min < max) { - index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN); - let child = trie[index + TRIE_PTR_IDX_IDX]; - if (child === TRIE_NULL) { - child = trie[TRIE_SIZE_IDX]; - if (child + TRIE_NODE_MEM > trie.length) { - trie = grow(trie, child + TRIE_NODE_MEM); - } - trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM; - trie[index + TRIE_PTR_IDX_IDX] = child; - trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX]; - } - index = child; - } - return [trie, index]; -} -function createTrie(id = 0, size = TRIE_DEFAULT_SIZE) { - size = Math.max(TRIE_MEM, size); - const buffer = new SharedArrayBuffer(size << 2); - const trie = new Int32Array(buffer); - trie[TRIE_SIZE_IDX] = TRIE_MEM; - trie[TRIE_ID_IDX] = id; - return trie; -} -function grow(trie, minSize = 0) { - const length = trie[TRIE_SIZE_IDX]; - minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR)); - const buffer = new SharedArrayBuffer(minSize << 2); - const next = new Int32Array(buffer); - for (let i = 0; i < length; ++i) { - next[i] = trie[i]; - } - return next; -} -function mergeLeft(tries, at, bt, mergeFn) { - const queue = [ - [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX] - ]; - do { - const Q = queue.length; - for (let q = 0; q < Q; ++q) { - let [at2, ai, bt2, bi] = queue[q]; - const bvi = tries[bt2][bi + TRIE_NODE_VALUE_IDX]; - if (bvi !== TRIE_NULL) { - const avi = tries[at2][ai + TRIE_NODE_VALUE_IDX]; - if (avi !== TRIE_NULL) { - mergeFn(avi, bvi); - } else { - tries[at2][ai + TRIE_NODE_VALUE_IDX] = bvi; - } - } - ai += TRIE_NODE_CHILDREN_IDX; - bi += TRIE_NODE_CHILDREN_IDX; - const bn = bi + TRIE_NODE_CHILDREN_MEM; - while (bi < bn) { - let ri = tries[bt2][bi + TRIE_PTR_IDX_IDX]; - if (ri === TRIE_NULL) { - ai += TRIE_PTR_MEM; - bi += TRIE_PTR_MEM; - continue; - } - const rt = tries[bt2][ri + TRIE_NODE_ID_IDX]; - if (bt2 !== rt) { - ri = tries[bt2][ri + TRIE_XPTR_IDX_IDX]; - } - let li = tries[at2][ai + TRIE_PTR_IDX_IDX]; - if (li === TRIE_NULL) { - li = tries[at2][TRIE_SIZE_IDX]; - if (li + TRIE_XPTR_MEM > tries[at2].length) { - tries[at2] = grow(tries[at2], li + TRIE_XPTR_MEM); - } - tries[at2][TRIE_SIZE_IDX] += TRIE_XPTR_MEM; - tries[at2][li + TRIE_XPTR_ID_IDX] = rt; - tries[at2][li + TRIE_XPTR_IDX_IDX] = ri; - } else { - const lt = tries[at2][li + TRIE_NODE_ID_IDX]; - if (at2 !== lt) { - ai = tries[at2][li + TRIE_XPTR_IDX_IDX]; - } - queue.push([lt, li, rt, ri]); - } - ai += TRIE_PTR_MEM; - bi += TRIE_PTR_MEM; - } - } - queue.splice(0, Q); - } while (queue.length > 0); -} -function print(tries, key, trieIndex, stream, separator = "", callbackFn) { - const stack = new Array(key.length + 1); - stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0]; - let top = 0; - let tail = false; - do { - let [trieI, childPtr, numChild] = stack[top]; - if (numChild >= TRIE_NODE_CHILDREN_LEN) { - --top; - continue; - } - stack[top][1] += TRIE_PTR_MEM; - ++stack[top][2]; - let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX]; - if (childI === TRIE_NULL) { - continue; - } - const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX]; - if (trieI !== childTrieI) { - childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX]; - trieI = childTrieI; - } - key[top] = numChild + UTF8_B0_MIN; - stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0]; - const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX]; - if (valueIndex !== TRIE_NULL) { - if (tail) { - stream.write(separator); - } - tail = true; - callbackFn(stream, key, top, valueIndex); - } - } while (top >= 0); -} - -async function run$1(filePath, workerPath, maxWorkers, outPath = "") { - maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS); - const chunks = await getFileChunks( - filePath, - maxWorkers, - ENTRY_MAX_LEN, - CHUNK_SIZE_MIN - ); - maxWorkers = chunks.length; - const valBuf = new SharedArrayBuffer(MAX_STATIONS * maxWorkers + 1 << 4); - const mins = new Int16Array(valBuf); - const maxes = new Int16Array(valBuf, 2); - const counts = new Uint32Array(valBuf, 4); - const sums = new Float64Array(valBuf, 8); - const tries = new Array(maxWorkers); - const workers = new Array(maxWorkers); - for (let i = 0; i < maxWorkers; ++i) { - const worker = new Worker(workerPath); - worker.on("error", (err) => { - throw err; - }); - worker.on("messageerror", (err) => { - throw err; - }); - worker.on("exit", (code) => { - if (code > 1 || code < 0) { - throw new Error(`Worker ${worker.threadId} exited with code ${code}`); - } - }); - workers[i] = worker; - } - const tasks = new Array(maxWorkers); - for (let i = 0; i < maxWorkers; ++i) { - const id = i; - const worker = workers[i]; - const [start, end] = chunks[i]; - tasks[i] = new Promise((resolve) => { - worker.once("message", resolve); - worker.postMessage({ - type: "process_request", - counts, - end, - filePath, - id, - maxes, - mins, - start, - sums - }); - }); - } - for await (const res of tasks) { - tries[res.id] = res.trie; - } - for (let i = 0, j = maxWorkers - 1; i < j; i = 0) { - const merges = []; - for (; i < j; ++i) { - const a = i; - const b = j--; - const worker = workers[i]; - merges.push(new Promise((resolve) => { - worker.once("message", resolve); - worker.postMessage({ - type: "merge_request", - a, - b, - counts, - maxes, - mins, - sums, - tries - }); - })); - } - for await (const res of merges) { - tries[res.id] = res.trie; - } - } - for (let i = 0; i < maxWorkers; ++i) { - await workers[i].terminate(); - } - const out = createWriteStream(outPath, { - fd: outPath.length < 1 ? 1 : void 0, - flags: "a", - highWaterMark: HIGH_WATER_MARK_OUT - }); - const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN); - out.write("{"); - print(tries, buffer, 0, out, ", ", printStation); - out.end("}\n"); - function printStation(stream, name, nameLen, vi) { - const avg = Math.round(sums[vi << 1] / counts[vi << 2]); - stream.write(name.toString("utf8", 0, nameLen)); - stream.write("="); - stream.write((mins[vi << 3] / 10).toFixed(1)); - stream.write("/"); - stream.write((avg / 10).toFixed(1)); - stream.write("/"); - stream.write((maxes[vi << 3] / 10).toFixed(1)); - } -} - -async function run({ - end, - filePath, - id, - start, - // Shared memory - counts, - maxes, - mins, - sums -}) { - if (start >= end) { - return { type: "process_response", id, trie: createTrie(id, 0) }; - } - let trie = createTrie(id); - let stations = id * MAX_STATIONS + 1; - const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN); - const stream = createReadStream(filePath, { - start, - end: end - 1, - highWaterMark: getHighWaterMark(end - start) - }); - let bufI = 0; - let tempI = 0; - let leaf; - for await (const chunk of stream) { - const N = chunk.length; - for (let i = 0; i < N; ++i) { - if (chunk[i] === CHAR_SEMICOLON) { - tempI = bufI; - } else if (chunk[i] !== CHAR_NEWLINE) { - buffer[bufI++] = chunk[i]; - } else { - const tempV = parseDouble(buffer, tempI, bufI); - bufI = 0; - [trie, leaf] = add(trie, buffer, 0, tempI); - if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) { - updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV); - } else { - trie[leaf + TRIE_NODE_VALUE_IDX] = stations; - newStation(stations++, tempV); - } - } - } - } - function newStation(index, temp) { - mins[index << 3] = temp; - maxes[index << 3] = temp; - counts[index << 2] = 1; - sums[index << 1] = temp; - } - function updateStation(index, temp) { - index <<= 3; - mins[index] = mins[index] <= temp ? mins[index] : temp; - maxes[index] = maxes[index] >= temp ? maxes[index] : temp; - ++counts[index >> 1]; - sums[index >> 2] += temp; - } - return { type: "process_response", id, trie }; -} -function parseDouble(b, min, max) { - if (b[min] === CHAR_MINUS) { - ++min; - return min + 4 > max ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11) : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111); - } - return min + 4 > max ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11 : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111; -} -function merge({ a, b, tries, counts, maxes, mins, sums }) { - mergeLeft(tries, a, b, mergeStations); - function mergeStations(ai, bi) { - ai <<= 3; - bi <<= 3; - mins[ai] = Math.min(mins[ai], mins[bi]); - maxes[ai] = Math.max(maxes[ai], maxes[bi]); - counts[ai >> 1] += counts[bi >> 1]; - sums[ai >> 2] += sums[bi >> 2]; - } - return { type: "merge_response", id: a, trie: tries[a] }; -} - -if (isMainThread) { - const workerPath = fileURLToPath(import.meta.url); - run$1(process.argv[2], workerPath, availableParallelism()); -} else { - parentPort.addListener("message", async (msg) => { - if (msg.type === "process_request") { - const res = await run(msg); - parentPort.postMessage(res); - } - if (msg.type === "merge_request") { - const res = merge(msg); - parentPort.postMessage(res); - } - }); -} +import{availableParallelism as z}from"node:os";import{fileURLToPath as Y}from"node:url";import{isMainThread as j,parentPort as L}from"node:worker_threads";import{createWriteStream as J,createReadStream as Q}from"node:fs";import{open as ee}from"fs/promises";import{Worker as te}from"worker_threads";const x=1e4,re=100,P=107,ne=45,U=10,se=59,W=48,C=32,oe=192,B=16384,ae=1048576,ie=1048576,_e=152e-6,ce=B,F=11*W,k=111*W,Ee=1,fe=512;function K(e,t,r){return e>t?e<=r?e:r:t}async function Ie(e,t,r,l=0){const o=await ee(e);try{const i=(await o.stat()).size,I=Math.max(l,Math.floor(i/t)),s=Buffer.allocUnsafe(r),a=[];let _=0;for(let f=I;f=0&&Ee.length&&(e=$(e,i+H)),e[g]+=H,e[o+p]=i,e[i+D]=e[G]),o=i}return[e,o]}function v(e=0,t=ue){t=Math.max(q,t);const r=new Int32Array(new SharedArrayBuffer(t<<2));return r[g]=q,r[G]=e,r}function $(e,t=0){const r=e[g];t=Math.max(t,Math.ceil(r*Re));const l=new Int32Array(new SharedArrayBuffer(t<<2));for(let o=0;oe[s].length&&(e[s]=$(e[s],m+S)),e[s][g]+=S,e[s][m+Te]=T,e[s][m+X]=u;else{const n=e[s][m+D];s!==n&&(a=e[s][m+X]),o.push([n,m,T,u])}a+=A,f+=A}}o.splice(0,i)}while(o.length>0)}function Ne(e,t,r,l,o="",i){const I=new Array(t.length+1);I[0]=[r,y+N,0];let s=0,a=!1;do{let[_,f,M]=I[s];if(M>=Z){--s;continue}I[s][1]+=A,++I[s][2];let E=e[_][f+p];if(E===w)continue;const u=e[_][E+D];_!==u&&(E=e[_][E+X],_=u),t[s]=M+C,I[++s]=[_,E+N,0];const T=e[_][E+d];T!==w&&(a&&l.write(o),a=!0,i(l,t,s,T))}while(s>=0)}function ye(e){const t=new te(e);return t.on("error",r=>{throw r}),t.on("messageerror",r=>{throw r}),t.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${t.threadId} exited with code ${r}`)}),t}function V(e,t){return new Promise(r=>{e.once("message",r),e.postMessage(t)})}async function Oe(e,t,r,l=""){r=K(r,Ee,fe);const o=await Ie(e,r,P,ce);r=o.length;const i=new SharedArrayBuffer(x*r+1<<4),I=new Int16Array(i),s=new Int16Array(i,2),a=new Uint32Array(i,4),_=new Float64Array(i,8),f=new Array(r),M=new Array(r);for(let n=0;n{f[c.id]=c.trie});for(let n=E.length-1;n>0;--n){const c=n-1>>1,R=n;E[c]=E[c].then(()=>E[R]).then(()=>V(M[c],{type:"merge_request",a:c,b:R,counts:a,maxes:s,mins:I,sums:_,tries:f})).then(h=>{f[h.id]=h.trie})}for(let n=0;nM[n].terminate());await Promise.all(E);const u=J(l,{fd:l.length<1?1:void 0,flags:"a",highWaterMark:ie}),T=Buffer.allocUnsafe(re);u.write("{"),Ne(f,T,0,u,", ",m),u.end(`} +`);function m(n,c,R,h){const O=Math.round(_[h<<1]/a[h<<2]);n.write(c.toString("utf8",0,R)),n.write("="),n.write((I[h<<3]/10).toFixed(1)),n.write("/"),n.write((O/10).toFixed(1)),n.write("/"),n.write((s[h<<3]/10).toFixed(1))}}async function Xe({end:e,filePath:t,id:r,start:l,counts:o,maxes:i,mins:I,sums:s}){if(l>=e)return{type:"process_response",id:r,trie:v(r,0)};let a=v(r),_=r*x+1;const f=Buffer.allocUnsafe(P),M=Q(t,{start:l,end:e-1,highWaterMark:le(e-l)});let E=0,u=0,T;for await(const c of M){const R=c.length;for(let h=0;h=R?i[c]:R,++o[c>>1],s[c>>2]+=R}return{type:"process_response",id:r,trie:a}}function He(e,t,r){return e[t]===ne?(++t,t+4>r?-(10*e[t]+e[t+2]-F):-(100*e[t]+10*e[t+1]+e[t+3]-k)):t+4>r?10*e[t]+e[t+2]-F:100*e[t]+10*e[t+1]+e[t+3]-k}function Le({a:e,b:t,tries:r,counts:l,maxes:o,mins:i,sums:I}){De(r,e,t,s);function s(a,_){a<<=3,_<<=3,i[a]=Math.min(i[a],i[_]),o[a]=Math.max(o[a],o[_]),l[a>>1]+=l[_>>1],I[a>>2]+=I[_>>2]}return{type:"merge_response",id:e,trie:r[e]}}if(j){const e=Y(import.meta.url);Oe(process.argv[2],e,z())}else L.addListener("message",async e=>{if(e.type==="process_request"){const t=await Xe(e);L.postMessage(t)}else if(e.type==="merge_request"){const t=Le(e);L.postMessage(t)}else throw new Error("Unknown message type")}); //# sourceMappingURL=index.mjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index cd6e948..8366093 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1 +1 @@ -{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN } from \"./utf8\";\n\n// Configurable constants\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 524288; // 2 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Internal trie pointer\n\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Cross-trie pointer (aka redirect)\n\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a null / undefined trie element.\n */\nexport const TRIE_NULL = 0;\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_PTR_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_XPTR_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach and initialize node\n trie[index + TRIE_PTR_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const buffer = new SharedArrayBuffer(size << 2);\n const trie = new Int32Array(buffer);\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const buffer = new SharedArrayBuffer(minSize << 2);\n const next = new Int32Array(buffer);\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_PTR_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_PTR_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Add new redirect\n tries[at][li + TRIE_XPTR_ID_IDX] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_B0_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n workers[i] = worker;\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n const id = i;\n const worker = workers[i];\n const [start, end] = chunks[i];\n tasks[i] = new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n type: \"process_request\",\n counts,\n end,\n filePath,\n id,\n maxes,\n mins,\n start,\n sums,\n } as ProcessRequest);\n });\n }\n\n // Wait for completion\n for await (const res of tasks) {\n tries[res.id] = res.trie;\n }\n\n // Merge tries\n for (let i = 0, j = maxWorkers - 1; i < j; i = 0) {\n const merges: Promise[] = [];\n for (; i < j; ++i) {\n const a = i;\n const b = j--;\n const worker = workers[i];\n merges.push(new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage({\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n } as MergeRequest);\n }));\n }\n for await (const res of merges) {\n tries[res.id] = res.trie;\n }\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n await workers[i].terminate();\n }\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\nexport function merge({a, b, tries, counts, maxes, mins, sums}: MergeRequest): MergeResponse {\n mergeLeft(tries, a, b, mergeStations);\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n return { type: \"merge_response\", id: a, trie: tries[a] };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n const res = await runWorker(msg as ProcessRequest);\n parentPort!.postMessage(res);\n }\n if (msg.type === \"merge_request\") {\n const res = merge(msg as MergeRequest);\n parentPort!.postMessage(res);\n }\n });\n}\n"],"names":["at","bt","run","runMain","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN } from \"./utf8\";\n\n// Configurable constants\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 524288; // 2 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Internal trie pointer\n\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Cross-trie pointer (aka redirect)\n\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a null / undefined trie element.\n */\nexport const TRIE_NULL = 0;\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_PTR_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_XPTR_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach and initialize node\n trie[index + TRIE_PTR_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_PTR_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_PTR_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Add new redirect\n tries[at][li + TRIE_XPTR_ID_IDX] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_B0_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n mergeLeft(tries, a, b, mergeStations);\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n return { type: \"merge_response\", id: a, trie: tries[a] };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n const res = await runWorker(msg as ProcessRequest);\n parentPort!.postMessage(res);\n } else if (msg.type === \"merge_request\") {\n const res = merge(msg as MergeRequest);\n parentPort!.postMessage(res);\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_B0_MIN","UTF8_B0_2B_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","CHAR_ZERO_11","CHAR_ZERO_111","MIN_WORKERS","MAX_WORKERS","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_IDX","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_IDX","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","stations","createReadStream","bufI","tempI","leaf","chunk","N","tempV","parseDouble","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/src/main.ts b/src/main/nodejs/havelessbemore/src/main.ts index 06732cb..30930a9 100644 --- a/src/main/nodejs/havelessbemore/src/main.ts +++ b/src/main/nodejs/havelessbemore/src/main.ts @@ -15,6 +15,7 @@ import { clamp, getFileChunks } from "./utils/stream"; import { print } from "./utils/utf8Trie"; import { MergeResponse } from "./types/mergeResponse"; import { MergeRequest } from "./types/mergeRequest"; +import { createWorker, exec } from "./utils/worker"; export async function run( filePath: string, @@ -47,58 +48,35 @@ export async function run( // Create workers const workers = new Array(maxWorkers); for (let i = 0; i < maxWorkers; ++i) { - const worker = new Worker(workerPath); - worker.on("error", (err) => { - throw err; - }); - worker.on("messageerror", (err) => { - throw err; - }); - worker.on("exit", (code) => { - if (code > 1 || code < 0) { - throw new Error(`Worker ${worker.threadId} exited with code ${code}`); - } - }); - workers[i] = worker; + workers[i] = createWorker(workerPath); } // Process each chunk - const tasks = new Array>(maxWorkers); + const tasks = new Array>(maxWorkers); for (let i = 0; i < maxWorkers; ++i) { - const id = i; - const worker = workers[i]; - const [start, end] = chunks[i]; - tasks[i] = new Promise((resolve) => { - worker.once("message", resolve); - worker.postMessage({ - type: "process_request", - counts, - end, - filePath, - id, - maxes, - mins, - start, - sums, - } as ProcessRequest); + tasks[i] = exec(workers[i], { + type: "process_request", + counts, + end: chunks[i][1], + filePath, + id: i, + maxes, + mins, + start: chunks[i][0], + sums, + }).then((res) => { + tries[res.id] = res.trie; }); } - // Wait for completion - for await (const res of tasks) { - tries[res.id] = res.trie; - } - // Merge tries - for (let i = 0, j = maxWorkers - 1; i < j; i = 0) { - const merges: Promise[] = []; - for (; i < j; ++i) { - const a = i; - const b = j--; - const worker = workers[i]; - merges.push(new Promise((resolve) => { - worker.once("message", resolve); - worker.postMessage({ + for (let i = tasks.length - 1; i > 0; --i) { + const a = (i - 1) >> 1; + const b = i; + tasks[a] = tasks[a] + .then(() => tasks[b]) + .then(() => + exec(workers[a], { type: "merge_request", a, b, @@ -107,19 +85,21 @@ export async function run( mins, sums, tries, - } as MergeRequest); - })); - } - for await (const res of merges) { - tries[res.id] = res.trie; - } + }), + ) + .then((res) => { + tries[res.id] = res.trie; + }); } // Terminate workers for (let i = 0; i < maxWorkers; ++i) { - await workers[i].terminate(); + tasks[i] = tasks[i].then(() => workers[i].terminate()); } + // Wait for completion + await Promise.all(tasks); + // Print results const out = createWriteStream(outPath, { fd: outPath.length < 1 ? 1 : undefined, From 4918ed66f8c4ffa8944cb7af1a7071583bc8c62f Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Thu, 23 May 2024 10:45:11 -0400 Subject: [PATCH 21/69] Add MIT license --- src/main/nodejs/havelessbemore/LICENSE | 21 +++ src/main/nodejs/havelessbemore/NOTICE | 23 +++ src/main/nodejs/havelessbemore/dist/index.cjs | 26 +++ .../nodejs/havelessbemore/dist/index.cjs.map | 2 +- src/main/nodejs/havelessbemore/dist/index.mjs | 26 +++ .../nodejs/havelessbemore/dist/index.mjs.map | 2 +- .../nodejs/havelessbemore/package-lock.json | 176 ++++++++++++++++++ src/main/nodejs/havelessbemore/package.json | 6 + .../nodejs/havelessbemore/rollup.config.ts | 12 ++ 9 files changed, 292 insertions(+), 2 deletions(-) create mode 100644 src/main/nodejs/havelessbemore/LICENSE create mode 100644 src/main/nodejs/havelessbemore/NOTICE diff --git a/src/main/nodejs/havelessbemore/LICENSE b/src/main/nodejs/havelessbemore/LICENSE new file mode 100644 index 0000000..c04820f --- /dev/null +++ b/src/main/nodejs/havelessbemore/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (C) 2024-2024 Michael Rojas + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/NOTICE b/src/main/nodejs/havelessbemore/NOTICE new file mode 100644 index 0000000..1614c55 --- /dev/null +++ b/src/main/nodejs/havelessbemore/NOTICE @@ -0,0 +1,23 @@ +<%= pkg.homepage %> + +MIT License + +Copyright (C) 2024-<%= moment().format('YYYY') %> <%= pkg.author %> + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs b/src/main/nodejs/havelessbemore/dist/index.cjs index 1dd4348..2d45441 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs +++ b/src/main/nodejs/havelessbemore/dist/index.cjs @@ -1,3 +1,29 @@ +/*! + * https://github.com/havelessbemore/1brc-nodejs + * + * MIT License + * + * Copyright (C) 2024-2024 Michael Rojas (https://github.com/havelessbemore) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + "use strict";var Y=require("node:os"),J=require("node:url"),X=require("node:worker_threads"),U=require("node:fs"),Q=require("fs/promises"),ee=require("worker_threads"),P=typeof document<"u"?document.currentScript:null;const x=1e4,te=100,W=107,re=45,C=10,ne=59,q=48,k=32,se=192,v=16384,ae=1048576,oe=1048576,ie=152e-6,_e=v,F=11*q,B=111*q,ce=1,ue=512;function b(e,t,r){return e>t?e<=r?e:r:t}async function Ee(e,t,r,l=0){const a=await Q.open(e);try{const i=(await a.stat()).size,f=Math.max(l,Math.floor(i/t)),s=Buffer.allocUnsafe(r),o=[];let _=0;for(let E=f;E=0&&ue.length&&(e=j(e,i+L)),e[g]+=L,e[a+p]=i,e[i+D]=e[G]),a=i}return[e,a]}function V(e=0,t=le){t=Math.max($,t);const r=new Int32Array(new SharedArrayBuffer(t<<2));return r[g]=$,r[G]=e,r}function j(e,t=0){const r=e[g];t=Math.max(t,Math.ceil(r*Ie));const l=new Int32Array(new SharedArrayBuffer(t<<2));for(let a=0;ae[s].length&&(e[s]=j(e[s],h+S)),e[s][g]+=S,e[s][h+Me]=T,e[s][h+H]=I;else{const n=e[s][h+D];s!==n&&(o=e[s][h+H]),a.push([n,h,T,I])}o+=m,E+=m}}a.splice(0,i)}while(a.length>0)}function De(e,t,r,l,a="",i){const f=new Array(t.length+1);f[0]=[r,N+y,0];let s=0,o=!1;do{let[_,E,M]=f[s];if(M>=K){--s;continue}f[s][1]+=m,++f[s][2];let u=e[_][E+p];if(u===w)continue;const I=e[_][u+D];_!==I&&(u=e[_][u+H],_=I),t[s]=M+k,f[++s]=[_,u+y,0];const T=e[_][u+A];T!==w&&(o&&l.write(a),o=!0,i(l,t,s,T))}while(s>=0)}function ye(e){const t=new ee.Worker(e);return t.on("error",r=>{throw r}),t.on("messageerror",r=>{throw r}),t.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${t.threadId} exited with code ${r}`)}),t}function z(e,t){return new Promise(r=>{e.once("message",r),e.postMessage(t)})}async function Ne(e,t,r,l=""){r=b(r,ce,ue);const a=await Ee(e,r,W,_e);r=a.length;const i=new SharedArrayBuffer(x*r+1<<4),f=new Int16Array(i),s=new Int16Array(i,2),o=new Uint32Array(i,4),_=new Float64Array(i,8),E=new Array(r),M=new Array(r);for(let n=0;n{E[c.id]=c.trie});for(let n=u.length-1;n>0;--n){const c=n-1>>1,R=n;u[c]=u[c].then(()=>u[R]).then(()=>z(M[c],{type:"merge_request",a:c,b:R,counts:o,maxes:s,mins:f,sums:_,tries:E})).then(d=>{E[d.id]=d.trie})}for(let n=0;nM[n].terminate());await Promise.all(u);const I=U.createWriteStream(l,{fd:l.length<1?1:void 0,flags:"a",highWaterMark:oe}),T=Buffer.allocUnsafe(te);I.write("{"),De(E,T,0,I,", ",h),I.end(`} `);function h(n,c,R,d){const O=Math.round(_[d<<1]/o[d<<2]);n.write(c.toString("utf8",0,R)),n.write("="),n.write((f[d<<3]/10).toFixed(1)),n.write("/"),n.write((O/10).toFixed(1)),n.write("/"),n.write((s[d<<3]/10).toFixed(1))}}async function Oe({end:e,filePath:t,id:r,start:l,counts:a,maxes:i,mins:f,sums:s}){if(l>=e)return{type:"process_response",id:r,trie:V(r,0)};let o=V(r),_=r*x+1;const E=Buffer.allocUnsafe(W),M=U.createReadStream(t,{start:l,end:e-1,highWaterMark:fe(e-l)});let u=0,I=0,T;for await(const c of M){const R=c.length;for(let d=0;d=R?i[c]:R,++a[c>>1],s[c>>2]+=R}return{type:"process_response",id:r,trie:o}}function Xe(e,t,r){return e[t]===re?(++t,t+4>r?-(10*e[t]+e[t+2]-F):-(100*e[t]+10*e[t+1]+e[t+3]-B)):t+4>r?10*e[t]+e[t+2]-F:100*e[t]+10*e[t+1]+e[t+3]-B}function He({a:e,b:t,tries:r,counts:l,maxes:a,mins:i,sums:f}){pe(r,e,t,s);function s(o,_){o<<=3,_<<=3,i[o]=Math.min(i[o],i[_]),a[o]=Math.max(a[o],a[_]),l[o>>1]+=l[_>>1],f[o>>2]+=f[_>>2]}return{type:"merge_response",id:e,trie:r[e]}}if(X.isMainThread){const e=J.fileURLToPath(typeof document>"u"?require("url").pathToFileURL(__filename).href:P&&P.src||new URL("index.cjs",document.baseURI).href);Ne(process.argv[2],e,Y.availableParallelism())}else X.parentPort.addListener("message",async e=>{if(e.type==="process_request"){const t=await Oe(e);X.parentPort.postMessage(t)}else if(e.type==="merge_request"){const t=He(e);X.parentPort.postMessage(t)}else throw new Error("Unknown message type")}); //# sourceMappingURL=index.cjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs.map b/src/main/nodejs/havelessbemore/dist/index.cjs.map index be01de4..e3bd30f 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.cjs.map @@ -1 +1 @@ -{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN } from \"./utf8\";\n\n// Configurable constants\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 524288; // 2 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Internal trie pointer\n\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Cross-trie pointer (aka redirect)\n\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a null / undefined trie element.\n */\nexport const TRIE_NULL = 0;\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_PTR_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_XPTR_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach and initialize node\n trie[index + TRIE_PTR_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_PTR_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_PTR_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Add new redirect\n tries[at][li + TRIE_XPTR_ID_IDX] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_B0_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n mergeLeft(tries, a, b, mergeStations);\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n return { type: \"merge_response\", id: a, trie: tries[a] };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n const res = await runWorker(msg as ProcessRequest);\n parentPort!.postMessage(res);\n } else if (msg.type === \"merge_request\") {\n const res = merge(msg as MergeRequest);\n parentPort!.postMessage(res);\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_B0_MIN","UTF8_B0_2B_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","CHAR_ZERO_11","CHAR_ZERO_111","MIN_WORKERS","MAX_WORKERS","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_IDX","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_IDX","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","stations","createReadStream","bufI","tempI","leaf","chunk","N","tempV","parseDouble","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","_documentCurrentScript","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN } from \"./utf8\";\n\n// Configurable constants\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 524288; // 2 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Internal trie pointer\n\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Cross-trie pointer (aka redirect)\n\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a null / undefined trie element.\n */\nexport const TRIE_NULL = 0;\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_PTR_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_XPTR_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach and initialize node\n trie[index + TRIE_PTR_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_PTR_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_PTR_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Add new redirect\n tries[at][li + TRIE_XPTR_ID_IDX] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_B0_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n mergeLeft(tries, a, b, mergeStations);\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n return { type: \"merge_response\", id: a, trie: tries[a] };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n const res = await runWorker(msg as ProcessRequest);\n parentPort!.postMessage(res);\n } else if (msg.type === \"merge_request\") {\n const res = merge(msg as MergeRequest);\n parentPort!.postMessage(res);\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_B0_MIN","UTF8_B0_2B_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","CHAR_ZERO_11","CHAR_ZERO_111","MIN_WORKERS","MAX_WORKERS","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_IDX","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_IDX","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","stations","createReadStream","bufI","tempI","leaf","chunk","N","tempV","parseDouble","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","_documentCurrentScript","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index 0c8111e..7561f4d 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -1,3 +1,29 @@ +/*! + * https://github.com/havelessbemore/1brc-nodejs + * + * MIT License + * + * Copyright (C) 2024-2024 Michael Rojas (https://github.com/havelessbemore) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + import{availableParallelism as z}from"node:os";import{fileURLToPath as Y}from"node:url";import{isMainThread as j,parentPort as L}from"node:worker_threads";import{createWriteStream as J,createReadStream as Q}from"node:fs";import{open as ee}from"fs/promises";import{Worker as te}from"worker_threads";const x=1e4,re=100,P=107,ne=45,U=10,se=59,W=48,C=32,oe=192,B=16384,ae=1048576,ie=1048576,_e=152e-6,ce=B,F=11*W,k=111*W,Ee=1,fe=512;function K(e,t,r){return e>t?e<=r?e:r:t}async function Ie(e,t,r,l=0){const o=await ee(e);try{const i=(await o.stat()).size,I=Math.max(l,Math.floor(i/t)),s=Buffer.allocUnsafe(r),a=[];let _=0;for(let f=I;f=0&&Ee.length&&(e=$(e,i+H)),e[g]+=H,e[o+p]=i,e[i+D]=e[G]),o=i}return[e,o]}function v(e=0,t=ue){t=Math.max(q,t);const r=new Int32Array(new SharedArrayBuffer(t<<2));return r[g]=q,r[G]=e,r}function $(e,t=0){const r=e[g];t=Math.max(t,Math.ceil(r*Re));const l=new Int32Array(new SharedArrayBuffer(t<<2));for(let o=0;oe[s].length&&(e[s]=$(e[s],m+S)),e[s][g]+=S,e[s][m+Te]=T,e[s][m+X]=u;else{const n=e[s][m+D];s!==n&&(a=e[s][m+X]),o.push([n,m,T,u])}a+=A,f+=A}}o.splice(0,i)}while(o.length>0)}function Ne(e,t,r,l,o="",i){const I=new Array(t.length+1);I[0]=[r,y+N,0];let s=0,a=!1;do{let[_,f,M]=I[s];if(M>=Z){--s;continue}I[s][1]+=A,++I[s][2];let E=e[_][f+p];if(E===w)continue;const u=e[_][E+D];_!==u&&(E=e[_][E+X],_=u),t[s]=M+C,I[++s]=[_,E+N,0];const T=e[_][E+d];T!==w&&(a&&l.write(o),a=!0,i(l,t,s,T))}while(s>=0)}function ye(e){const t=new te(e);return t.on("error",r=>{throw r}),t.on("messageerror",r=>{throw r}),t.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${t.threadId} exited with code ${r}`)}),t}function V(e,t){return new Promise(r=>{e.once("message",r),e.postMessage(t)})}async function Oe(e,t,r,l=""){r=K(r,Ee,fe);const o=await Ie(e,r,P,ce);r=o.length;const i=new SharedArrayBuffer(x*r+1<<4),I=new Int16Array(i),s=new Int16Array(i,2),a=new Uint32Array(i,4),_=new Float64Array(i,8),f=new Array(r),M=new Array(r);for(let n=0;n{f[c.id]=c.trie});for(let n=E.length-1;n>0;--n){const c=n-1>>1,R=n;E[c]=E[c].then(()=>E[R]).then(()=>V(M[c],{type:"merge_request",a:c,b:R,counts:a,maxes:s,mins:I,sums:_,tries:f})).then(h=>{f[h.id]=h.trie})}for(let n=0;nM[n].terminate());await Promise.all(E);const u=J(l,{fd:l.length<1?1:void 0,flags:"a",highWaterMark:ie}),T=Buffer.allocUnsafe(re);u.write("{"),Ne(f,T,0,u,", ",m),u.end(`} `);function m(n,c,R,h){const O=Math.round(_[h<<1]/a[h<<2]);n.write(c.toString("utf8",0,R)),n.write("="),n.write((I[h<<3]/10).toFixed(1)),n.write("/"),n.write((O/10).toFixed(1)),n.write("/"),n.write((s[h<<3]/10).toFixed(1))}}async function Xe({end:e,filePath:t,id:r,start:l,counts:o,maxes:i,mins:I,sums:s}){if(l>=e)return{type:"process_response",id:r,trie:v(r,0)};let a=v(r),_=r*x+1;const f=Buffer.allocUnsafe(P),M=Q(t,{start:l,end:e-1,highWaterMark:le(e-l)});let E=0,u=0,T;for await(const c of M){const R=c.length;for(let h=0;h=R?i[c]:R,++o[c>>1],s[c>>2]+=R}return{type:"process_response",id:r,trie:a}}function He(e,t,r){return e[t]===ne?(++t,t+4>r?-(10*e[t]+e[t+2]-F):-(100*e[t]+10*e[t+1]+e[t+3]-k)):t+4>r?10*e[t]+e[t+2]-F:100*e[t]+10*e[t+1]+e[t+3]-k}function Le({a:e,b:t,tries:r,counts:l,maxes:o,mins:i,sums:I}){De(r,e,t,s);function s(a,_){a<<=3,_<<=3,i[a]=Math.min(i[a],i[_]),o[a]=Math.max(o[a],o[_]),l[a>>1]+=l[_>>1],I[a>>2]+=I[_>>2]}return{type:"merge_response",id:e,trie:r[e]}}if(j){const e=Y(import.meta.url);Oe(process.argv[2],e,z())}else L.addListener("message",async e=>{if(e.type==="process_request"){const t=await Xe(e);L.postMessage(t)}else if(e.type==="merge_request"){const t=Le(e);L.postMessage(t)}else throw new Error("Unknown message type")}); //# sourceMappingURL=index.mjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index 8366093..21da856 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1 +1 @@ -{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN } from \"./utf8\";\n\n// Configurable constants\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 524288; // 2 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Internal trie pointer\n\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Cross-trie pointer (aka redirect)\n\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a null / undefined trie element.\n */\nexport const TRIE_NULL = 0;\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_PTR_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_XPTR_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach and initialize node\n trie[index + TRIE_PTR_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_PTR_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_PTR_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Add new redirect\n tries[at][li + TRIE_XPTR_ID_IDX] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_B0_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n mergeLeft(tries, a, b, mergeStations);\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n return { type: \"merge_response\", id: a, trie: tries[a] };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n const res = await runWorker(msg as ProcessRequest);\n parentPort!.postMessage(res);\n } else if (msg.type === \"merge_request\") {\n const res = merge(msg as MergeRequest);\n parentPort!.postMessage(res);\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_B0_MIN","UTF8_B0_2B_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","CHAR_ZERO_11","CHAR_ZERO_111","MIN_WORKERS","MAX_WORKERS","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_IDX","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_IDX","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","stations","createReadStream","bufI","tempI","leaf","chunk","N","tempV","parseDouble","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN } from \"./utf8\";\n\n// Configurable constants\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 524288; // 2 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Internal trie pointer\n\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Cross-trie pointer (aka redirect)\n\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a null / undefined trie element.\n */\nexport const TRIE_NULL = 0;\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_PTR_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_XPTR_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach and initialize node\n trie[index + TRIE_PTR_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_PTR_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_PTR_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Add new redirect\n tries[at][li + TRIE_XPTR_ID_IDX] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_B0_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n mergeLeft(tries, a, b, mergeStations);\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n return { type: \"merge_response\", id: a, trie: tries[a] };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n const res = await runWorker(msg as ProcessRequest);\n parentPort!.postMessage(res);\n } else if (msg.type === \"merge_request\") {\n const res = merge(msg as MergeRequest);\n parentPort!.postMessage(res);\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_B0_MIN","UTF8_B0_2B_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","CHAR_ZERO_11","CHAR_ZERO_111","MIN_WORKERS","MAX_WORKERS","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_IDX","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_IDX","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","stations","createReadStream","bufI","tempI","leaf","chunk","N","tempV","parseDouble","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/package-lock.json b/src/main/nodejs/havelessbemore/package-lock.json index 3ff8fa1..85d7206 100644 --- a/src/main/nodejs/havelessbemore/package-lock.json +++ b/src/main/nodejs/havelessbemore/package-lock.json @@ -4,6 +4,7 @@ "requires": true, "packages": { "": { + "license": "MIT", "devDependencies": { "@rollup/plugin-typescript": "^11.1.6", "@types/node": "^20.10.6", @@ -14,6 +15,7 @@ "rimraf": "^5.0.7", "rollup": "^4.17.2", "rollup-plugin-esbuild": "^6.1.1", + "rollup-plugin-license": "^3.4.0", "tinybench": "^2.8.0", "tslib": "^2.6.2", "tsx": "^4.10.5", @@ -525,6 +527,12 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1123,6 +1131,15 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, + "node_modules/array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -1203,6 +1220,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/commenting": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/commenting/-/commenting-1.1.0.tgz", + "integrity": "sha512-YeNK4tavZwtH7jEgK1ZINXzLKm6DZdEMfsaaieOsCAN0S8vsY7UeuO3Q7d/M018EFgE+IeUAuBOKkFccBZsUZA==", + "dev": true + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -2026,6 +2049,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -2041,6 +2070,15 @@ "node": "14 || >=16.14" } }, + "node_modules/magic-string": { + "version": "0.30.10", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", + "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + } + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -2096,6 +2134,30 @@ "node": ">=16 || 14 >=14.17" } }, + "node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "dev": true, + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -2164,6 +2226,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/package-name-regex": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/package-name-regex/-/package-name-regex-2.0.6.tgz", + "integrity": "sha512-gFL35q7kbE/zBaPA3UKhp2vSzcPYx2ecbYuwv1ucE9Il6IIgBDweBlH8D68UFGZic2MkllKa2KHCfC1IQBQUYA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/dword-design" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -2416,6 +2490,49 @@ "rollup": "^1.20.0 || ^2.0.0 || ^3.0.0 || ^4.0.0" } }, + "node_modules/rollup-plugin-license": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-license/-/rollup-plugin-license-3.4.0.tgz", + "integrity": "sha512-Nwx4dDjoPlzR7QWcsswezxFAOC000+JLACganH3L+5toit0TEAfD4SF1DsvJR/kunHWJgqnhmzvOO+iLI1oKPw==", + "dev": true, + "dependencies": { + "commenting": "~1.1.0", + "glob": "~7.2.0", + "lodash": "~4.17.21", + "magic-string": "~0.30.0", + "mkdirp": "~3.0.0", + "moment": "~2.30.1", + "package-name-regex": "~2.0.6", + "spdx-expression-validate": "~2.0.0", + "spdx-satisfies": "~5.0.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.0.0 || ^2.0.0 || ^3.0.0 || ^4.0.0" + } + }, + "node_modules/rollup-plugin-license/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -2493,6 +2610,65 @@ "node": ">=8" } }, + "node_modules/spdx-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/spdx-compare/-/spdx-compare-1.0.0.tgz", + "integrity": "sha512-C1mDZOX0hnu0ep9dfmuoi03+eOdDoz2yvK79RxbcrVEG1NO1Ph35yW102DHWKN4pk80nwCgeMmSY5L25VE4D9A==", + "dev": true, + "dependencies": { + "array-find-index": "^1.0.2", + "spdx-expression-parse": "^3.0.0", + "spdx-ranges": "^2.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-expression-validate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-validate/-/spdx-expression-validate-2.0.0.tgz", + "integrity": "sha512-b3wydZLM+Tc6CFvaRDBOF9d76oGIHNCLYFeHbftFXUWjnfZWganmDmvtM5sm1cRwJc/VDBMLyGGrsLFd1vOxbg==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz", + "integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==", + "dev": true + }, + "node_modules/spdx-ranges": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/spdx-ranges/-/spdx-ranges-2.1.1.tgz", + "integrity": "sha512-mcdpQFV7UDAgLpXEE/jOMqvK4LBoO0uTQg0uvXUewmEFhpiZx5yJSZITHB8w1ZahKdhfZqP5GPEOKLyEq5p8XA==", + "dev": true + }, + "node_modules/spdx-satisfies": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/spdx-satisfies/-/spdx-satisfies-5.0.1.tgz", + "integrity": "sha512-Nwor6W6gzFp8XX4neaKQ7ChV4wmpSh2sSDemMFSzHxpTw460jxFYeOn+jq4ybnSSw/5sc3pjka9MQPouksQNpw==", + "dev": true, + "dependencies": { + "spdx-compare": "^1.0.0", + "spdx-expression-parse": "^3.0.0", + "spdx-ranges": "^2.0.0" + } + }, "node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", diff --git a/src/main/nodejs/havelessbemore/package.json b/src/main/nodejs/havelessbemore/package.json index 95ac107..5a46854 100644 --- a/src/main/nodejs/havelessbemore/package.json +++ b/src/main/nodejs/havelessbemore/package.json @@ -1,4 +1,9 @@ { + "description": "Submission for the One Billion Row Challenge", + "license": "MIT", + "author": "Michael Rojas (https://github.com/havelessbemore)", + "homepage": "https://github.com/havelessbemore/1brc-nodejs", + "bugs": "https://github.com/havelessbemore/1brc-nodejs/issues", "sideEffects": false, "engines": { "node": ">= 18" @@ -30,6 +35,7 @@ "rimraf": "^5.0.7", "rollup": "^4.17.2", "rollup-plugin-esbuild": "^6.1.1", + "rollup-plugin-license": "^3.4.0", "tinybench": "^2.8.0", "tslib": "^2.6.2", "tsx": "^4.10.5", diff --git a/src/main/nodejs/havelessbemore/rollup.config.ts b/src/main/nodejs/havelessbemore/rollup.config.ts index bbc7b9c..a67a998 100644 --- a/src/main/nodejs/havelessbemore/rollup.config.ts +++ b/src/main/nodejs/havelessbemore/rollup.config.ts @@ -1,5 +1,6 @@ import { RollupOptions } from "rollup"; import esbuild from "rollup-plugin-esbuild"; +import license, { Options as LicenseOptions } from "rollup-plugin-license"; import pkg from "./package.json" with { type: "json" }; @@ -11,6 +12,16 @@ function bundle(config: RollupOptions): RollupOptions { }; } +const licenseConfig: LicenseOptions = { + sourcemap: true, + banner: { + commentStyle: "ignored", + content: { + file: "./NOTICE", + }, + }, +}; + export default [ bundle({ plugins: [ @@ -18,6 +29,7 @@ export default [ target: "ES2022", minify: true, }), + license(licenseConfig), ], output: [ { From 81108790b9cea8dd46b6b9547207580f98f64187 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Thu, 23 May 2024 11:09:53 -0400 Subject: [PATCH 22/69] Update linter config --- src/main/nodejs/havelessbemore/benchmarks/bench.ts | 4 ++-- src/main/nodejs/havelessbemore/dist/index.cjs.map | 2 +- src/main/nodejs/havelessbemore/dist/index.mjs.map | 2 +- src/main/nodejs/havelessbemore/eslint.config.js | 12 +----------- src/main/nodejs/havelessbemore/package.json | 2 +- src/main/nodejs/havelessbemore/src/main.ts | 2 +- src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts | 4 +++- 7 files changed, 10 insertions(+), 18 deletions(-) diff --git a/src/main/nodejs/havelessbemore/benchmarks/bench.ts b/src/main/nodejs/havelessbemore/benchmarks/bench.ts index 83b2c3d..86437af 100644 --- a/src/main/nodejs/havelessbemore/benchmarks/bench.ts +++ b/src/main/nodejs/havelessbemore/benchmarks/bench.ts @@ -48,11 +48,11 @@ await rm(dir, { recursive: true, force: true }); // REPORTING function toRecord(task: Task): Record { const out: Record = {}; - out["Name"] = task.name; + out.Name = task.name; out["Min (s)"] = toSeconds(task.result?.min); out["Max (s)"] = toSeconds(task.result?.max); out["Avg (s)"] = toSeconds(task.result?.mean); - out["Samples"] = +(task.result?.samples ?? []).length; + out.Samples = +(task.result?.samples ?? []).length; return out; } diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs.map b/src/main/nodejs/havelessbemore/dist/index.cjs.map index e3bd30f..a420ee2 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.cjs.map @@ -1 +1 @@ -{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN } from \"./utf8\";\n\n// Configurable constants\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 524288; // 2 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Internal trie pointer\n\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Cross-trie pointer (aka redirect)\n\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a null / undefined trie element.\n */\nexport const TRIE_NULL = 0;\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_PTR_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_XPTR_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach and initialize node\n trie[index + TRIE_PTR_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_PTR_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_PTR_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Add new redirect\n tries[at][li + TRIE_XPTR_ID_IDX] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_B0_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n mergeLeft(tries, a, b, mergeStations);\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n return { type: \"merge_response\", id: a, trie: tries[a] };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n const res = await runWorker(msg as ProcessRequest);\n parentPort!.postMessage(res);\n } else if (msg.type === \"merge_request\") {\n const res = merge(msg as MergeRequest);\n parentPort!.postMessage(res);\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_B0_MIN","UTF8_B0_2B_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","CHAR_ZERO_11","CHAR_ZERO_111","MIN_WORKERS","MAX_WORKERS","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_IDX","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_IDX","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","stations","createReadStream","bufI","tempI","leaf","chunk","N","tempV","parseDouble","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","_documentCurrentScript","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN } from \"./utf8\";\n\n// Configurable constants\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 524288; // 2 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Internal trie pointer\n\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Cross-trie pointer (aka redirect)\n\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a null / undefined trie element.\n */\nexport const TRIE_NULL = 0;\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_PTR_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_XPTR_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach and initialize node\n trie[index + TRIE_PTR_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_PTR_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_PTR_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Add new redirect\n tries[at][li + TRIE_XPTR_ID_IDX] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_B0_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n mergeLeft(tries, a, b, mergeStations);\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n return { type: \"merge_response\", id: a, trie: tries[a] };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n const res = await runWorker(msg as ProcessRequest);\n parentPort!.postMessage(res);\n } else if (msg.type === \"merge_request\") {\n const res = merge(msg as MergeRequest);\n parentPort!.postMessage(res);\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_B0_MIN","UTF8_B0_2B_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","CHAR_ZERO_11","CHAR_ZERO_111","MIN_WORKERS","MAX_WORKERS","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_IDX","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_IDX","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","stations","createReadStream","bufI","tempI","leaf","chunk","N","tempV","parseDouble","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","_documentCurrentScript","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index 21da856..10fc1db 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1 +1 @@ -{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN } from \"./utf8\";\n\n// Configurable constants\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 524288; // 2 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Internal trie pointer\n\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Cross-trie pointer (aka redirect)\n\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a null / undefined trie element.\n */\nexport const TRIE_NULL = 0;\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_PTR_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_XPTR_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach and initialize node\n trie[index + TRIE_PTR_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_PTR_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_PTR_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Add new redirect\n tries[at][li + TRIE_XPTR_ID_IDX] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack: [number, number, number][] = new Array(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_B0_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries: Int32Array[] = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n mergeLeft(tries, a, b, mergeStations);\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n return { type: \"merge_response\", id: a, trie: tries[a] };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n const res = await runWorker(msg as ProcessRequest);\n parentPort!.postMessage(res);\n } else if (msg.type === \"merge_request\") {\n const res = merge(msg as MergeRequest);\n parentPort!.postMessage(res);\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_B0_MIN","UTF8_B0_2B_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","CHAR_ZERO_11","CHAR_ZERO_111","MIN_WORKERS","MAX_WORKERS","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_IDX","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_IDX","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","stations","createReadStream","bufI","tempI","leaf","chunk","N","tempV","parseDouble","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;0SAGO,CAKMA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAe,IAKfC,CAAuB,CAAA,CAAA,CAAA,CAAA,CAAA,CAWvBC,CAAgB,CAAA,CAAA,CAAA,CAAA,CCnBhBC,CAAa,CAAA,CAAA,CAAA,CAAA,CAKbC,CAAe,CAAA,CAAA,CAAA,CAUfC,CAAiB,CAAA,CAAA,CAAA,CAAA,CAKjBC,CAAY,CAAA,CAAA,CAAA,CAWZC,CAAc,CAAA,CAAA,CAAA,CA6BdC,CAAiB,CAAA,CAAA,CAAA,CAAA,CAAA,CC5DjBC,EAAsB,CAKtBC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAsB,CAKtBC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAsB,CAMtBC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAwB,CAKxBC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAiBJ,EAOjBK,CAAe,CAAA,CAAA,CAAA,CAAKR,CAKpBS,CAAAA,CAAAA,CAAgB,CAAMT,CAAAA,CAAAA,CAAAA,CAAAA,CCnCtBU,CAAc,CAAA,CAAA,CAAA,CAKdC,GAAc,aCUXC,CAAMC,CAAAA,CAAAA,CAAeC,CAAaC,CAAAA,CAAAA,CAAqB,CACrE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAOF,CAAQC,CAAAA,CAAAA,CAAOD,CAASE,CAAAA,CAAAA,CAAAA,CAAMF,CAAQE,CAAAA,CAAAA,CAAOD,CACtD,gBAoBsBE,CACpBC,CAAAA,CAAAA,CAAAA,CACAC,CACAC,CAAAA,CAAAA,CACAC,CAAU,CAAA,CAAA,CACmB,CAE7B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMC,EAAO,CAAMC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAKL,CAAQ,CAAA,CAChC,CAAI,CAAA,CAAA,CAEF,CAAMM,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAQ,MAAMF,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,EAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAE3BG,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAIJ,CAAAA,CAAAA,CAAAA,CAAAA,CAAS,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMG,CAAOL,CAAAA,CAAM,CAAC,CAAA,CAEvDO,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,YAAYN,CAAa,CAAA,CACzCO,CAA6B,CAAA,EAEnC,CAAA,CAAA,CAAA,CAAA,CAAIC,CAAQ,CAAA,CAAA,CACZ,QAASC,CAAMJ,CAAAA,CAAAA,CAAWI,CAAML,CAAAA,CAAAA,CAAMK,CAAOJ,CAAAA,CAAAA,CAAAA,CAAW,CAEtD,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMK,EAAM,CAAMR,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAK,CAAKI,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAQ,CAAGN,CAAAA,CAAAA,CAAeS,CAAG,CAAA,CAEnDE,CAAUL,CAAAA,CAAAA,CAAO,CAAQ3B,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAY,CAEvCgC,CAAAA,CAAAA,CAAAA,CAAW,CAAKA,CAAAA,CAAAA,CAAAA,CAAUD,EAAI,CAEhCD,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAOE,CAAU,CAAA,CAAA,CAEjBJ,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAACC,CAAAA,CAAOC,CAAG,CAAC,CAAA,CAExBD,CAAQC,CAAAA,CAAAA,CAEZ,CAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAID,CAAQJ,CAAAA,CAAAA,CAAAA,CACVG,EAAO,CAAK,CAAA,CAAA,CAAA,CAAA,CAACC,CAAOJ,CAAAA,CAAI,CAAC,CAAA,CAGpBG,CACT,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAML,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EACb,CACF,CASO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAASU,GAAiBR,CAAsB,CAAA,CAErD,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAQjB,CAERiB,CAAAA,CAAAA,CAAAA,CAAO,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,KAAK,CAAKA,CAAAA,CAAAA,CAAAA,CAAAA,CAAI,CAAC,CAAA,CAEjCA,CAAO,CAAA,CAAA,CAAA,CAAKA,CAELX,CAAAA,CAAAA,CAAMW,EAAMpB,CAAqBC,CAAAA,CAAAA,CAAmB,CAC7D,CC9Fa,CAAA4B,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAoB,CAKpBC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAqB,CAIrBC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAmB,CACnBC,CAAAA,CAAAA,CAAAA,CAAmB,CAEnBC,CAAAA,CAAAA,CAAeD,CAIfE,CAAAA,CAAAA,CAAAA,CAAAA,CAAmB,EACnBC,CAAmB,CAAA,CAAA,CAAA,CAEnBC,CAAoB,CAAA,CAAA,CACpBC,CAAoB,CAAA,CAAA,CAAA,CAEpBC,CAAgBH,CAAAA,CAAAA,CAAAA,CAAmBE,GAInCE,CAAmB,CAAA,CAAA,CACnBC,CAAmB,CAAA,CAAA,CAAA,CAEnBC,CAAsB,CAAA,CAAA,CACtBC,CAAsB,CAAA,CAAA,CAAA,CAEtBC,EAAyB,CACzBC,CAAAA,CAAAA,CAAyB7C,CACzB8C,CAAAA,CAAAA,CAAAA,CAAyBZ,CAAeW,CAAAA,CAAAA,CAExCE,CACXN,CAAAA,CAAAA,CAAAA,CAAmBE,CAAsBG,CAAAA,CAAAA,CAAAA,CAO9BE,CAAY,CAAA,CAAA,CAEZC,CAAgB,CAAA,CAAA,CAChBC,CAAgB,CAAA,CAAA,CAAA,CAEhBC,EAAgB,CAChBC,CAAAA,CAAAA,CAAAA,CAAgBL,CAEhBM,CAAAA,CAAAA,CAAcF,CAAgBX,CAAAA,CAAAA,CAC9Bc,CAAWJ,CAAAA,CAAAA,CAAAA,CAAgBE,GCpCjC,CAASG,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACdC,CACAC,CAAAA,CAAAA,CACA7C,CACAC,CAAAA,CAAAA,CACsB,CACtB,CAAA,CAAA,CAAA,CAAI6C,EAAQP,CACZ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAOvC,CAAMC,CAAAA,CAAAA,CAAAA,CAAK,CAChB6C,CAAAA,CAAAA,CAASd,CAAyBV,CAAAA,CAAAA,CAAAA,CAAgBuB,CAAI7C,CAAAA,CAAAA,CAAAA,CAAK,CAAIb,CAAAA,CAAAA,CAAAA,CAC/D,CAAI4D,CAAAA,CAAAA,CAAAA,CAAAA,CAAQH,CAAKE,CAAAA,CAAAA,CAAQ1B,CAAgB,CACrC2B,CAAAA,CAAAA,CAAAA,CAAAA,CAAUX,CAEZW,CAAAA,CAAAA,CAAAA,CAAAA,CAAQH,CAAKP,CAAAA,CAAa,CACtBU,CAAAA,CAAAA,CAAQZ,EAAgBS,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAC/BA,CAAOI,CAAAA,CAAAA,CAAKJ,CAAMG,CAAAA,CAAAA,CAAQZ,CAAa,CAAA,CAAA,CAEzCS,EAAKP,CAAa,CAAA,CAAA,CAAKF,CAEvBS,CAAAA,CAAAA,CAAKE,CAAQ1B,CAAAA,CAAgB,CAAI2B,CAAAA,CAAAA,CACjCH,CAAKG,CAAAA,CAAAA,CAAQnB,CAAgB,CAAA,CAAIgB,CAAKH,CAAAA,CAAW,CAEnDK,CAAAA,CAAAA,CAAAA,CAAQC,CACV,CAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAACH,CAAAA,CAAME,CAAK,CACrB,CAEO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAASG,EAAWC,CAAK,CAAA,CAAA,CAAGzC,CAAOS,CAAAA,CAAAA,CAAAA,CAA+B,CACvET,CAAAA,CAAO,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAIiC,EAAUjC,CAAI,CAAA,CAC9B,CAAMmC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAO,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAkBnC,CAAQ,CAAA,CAAA,CAAC,CAAC,CAAA,CAC5D,CAAAmC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAKP,CAAa,CAAA,CAAIK,EACtBE,CAAKH,CAAAA,CAAW,CAAIS,CAAAA,CAAAA,CACbN,CACT,CAEO,CAASI,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAKJ,EAAkBtC,CAAU,CAAA,CAAA,CAAe,CAC9D,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM6C,CAASP,CAAAA,CAAAA,CAAKP,CAAa,CAAA,CACjC/B,EAAU,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAIA,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAK6C,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAShC,CAAkB,CAAA,CAAC,CAClE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMiC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAI,CAAW,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAkB9C,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAW,CAAC,CAAC,CAAA,CAC/D,CAAS+C,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAI,CAAGA,CAAAA,CAAAA,CAAIF,CAAQ,CAAA,CAAA,CAAEE,EAC5BD,CAAKC,CAAAA,CAAC,CAAIT,CAAAA,CAAAA,CAAKS,CAAC,CAAA,CAElB,CAAOD,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACT,CAEO,CAASE,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACdC,CACAC,CAAAA,CAAAA,CACAC,CACAC,CAAAA,CAAAA,CACM,CACN,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMC,CAA4C,CAAA,CAChD,CAACH,CAAAA,CAAIjB,CAAekB,CAAAA,CAAAA,CAAIlB,CAAa,CACvC,EAEA,CAAG,CAAA,CACD,CAAMqB,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAID,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAChB,CAASE,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAI,EAAGA,CAAID,CAAAA,CAAAA,CAAG,CAAEC,CAAAA,CAAAA,CAAG,CAC1B,CAAA,CAAA,CAAI,CAACL,CAAAA,CAAIM,EAAIL,CAAIM,CAAAA,CAAE,CAAIJ,CAAAA,CAAAA,CAAME,CAAC,CAAA,CAG9B,CAAMG,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAMT,CAAME,CAAAA,CAAE,CAAEM,CAAAA,CAAAA,CAAKjC,CAAmB,CAAA,CAC9C,CAAIkC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAQ5B,EAAW,CAErB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM6B,CAAMV,CAAAA,CAAAA,CAAMC,CAAE,CAAA,CAAEM,CAAKhC,CAAAA,CAAmB,EAC1CmC,CAAQ7B,CAAAA,CAAAA,CAAAA,CAAAA,CACVsB,CAAQO,CAAAA,CAAAA,CAAKD,CAAG,CAAA,CAEhBT,CAAMC,CAAAA,CAAE,EAAEM,CAAKhC,CAAAA,CAAmB,CAAIkC,CAAAA,CAE1C,CAGAF,CAAAA,CAAAA,CAAM9B,CACN+B,CAAAA,CAAAA,CAAAA,CAAM/B,CAGN,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMkC,CAAKH,CAAAA,CAAAA,CAAK7B,CAChB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO6B,CAAKG,CAAAA,CAAAA,CAAAA,CAAI,CAEd,CAAIC,CAAAA,CAAAA,CAAAA,CAAAA,CAAKZ,CAAME,CAAAA,CAAE,CAAEM,CAAAA,CAAAA,CAAK3C,CAAgB,CAAA,CACxC,GAAI+C,CAAO/B,CAAAA,CAAAA,CAAAA,CAAAA,CAAW,CAEpB0B,CAAAA,CAAAA,CAAMxC,CACNyC,CAAAA,CAAAA,CAAAA,CAAMzC,CACN,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACF,CAGA,CAAM8C,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAKb,CAAME,CAAAA,CAAE,CAAEU,CAAAA,CAAAA,CAAKvC,CAAgB,CAAA,CACtC6B,CAAOW,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACTD,CAAKZ,CAAAA,CAAAA,CAAME,CAAE,CAAA,CAAEU,CAAK1C,CAAAA,CAAiB,GAIvC,CAAI4C,CAAAA,CAAAA,CAAAA,CAAAA,CAAKd,CAAMC,CAAAA,CAAE,CAAEM,CAAAA,CAAAA,CAAK1C,CAAgB,CAAA,CACxC,GAAIiD,CAAOjC,CAAAA,CAAAA,CAAAA,CAAAA,CAETiC,CAAKd,CAAAA,CAAAA,CAAMC,CAAE,CAAA,CAAEnB,CAAa,CAAA,CACxBgC,EAAK1C,CAAgB4B,CAAAA,CAAAA,CAAMC,CAAE,CAAA,CAAE,CACjCD,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAMC,CAAE,CAAA,CAAIR,CAAKO,CAAAA,CAAAA,CAAMC,CAAE,CAAA,CAAGa,CAAK1C,CAAAA,CAAa,CAEhD4B,CAAAA,CAAAA,CAAAA,CAAMC,CAAE,CAAEnB,CAAAA,CAAa,CAAKV,CAAAA,CAAAA,CAAAA,CAE5B4B,CAAMC,CAAAA,CAAE,CAAEa,CAAAA,CAAAA,CAAK9C,CAAgB,CAAA,CAAA,CAAI6C,CACnCb,CAAAA,CAAAA,CAAMC,CAAE,CAAA,CAAEa,CAAK5C,CAAAA,CAAiB,EAAI0C,CAC/B,CAAA,CAAA,CAAA,CAAA,CAAA,CAEL,CAAMG,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAKf,CAAMC,CAAAA,CAAE,CAAEa,CAAAA,CAAAA,CAAKzC,CAAgB,CAAA,CACtC4B,CAAOc,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACTR,CAAKP,CAAAA,CAAAA,CAAMC,CAAE,CAAA,CAAEa,EAAK5C,CAAiB,CAAA,CAAA,CAGvCkC,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAACW,CAAAA,CAAID,CAAID,CAAAA,CAAAA,CAAID,CAAE,CAAC,CAC7B,CAGAL,CAAAA,CAAAA,CAAMxC,CACNyC,CAAAA,CAAAA,CAAAA,CAAMzC,CACR,CACF,CACAqC,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAGC,CAAAA,CAAC,CACnB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAASD,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAC1B,CAAA,CAEO,CAASY,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACdhB,CACAV,CAAAA,CAAAA,CACA2B,CACAC,CAAAA,CAAAA,CACAC,EAAY,CACZC,CAAAA,CAAAA,CAAAA,CAMM,CACN,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMC,CAAoC,CAAA,CAAA,CAAA,CAAA,CAAI,CAAM/B,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAI,OAAS,CAAC,CAAA,CAClE+B,CAAM,CAAA,CAAC,CAAI,CAAA,CAACJ,CAAWjC,CAAAA,CAAAA,CAAgBP,EAAwB,CAAC,CAAA,CAEhE,CAAI6C,CAAAA,CAAAA,CAAAA,CAAAA,CAAM,CACNC,CAAAA,CAAAA,CAAO,CACX,CAAA,CAAA,CAAA,CAAG,CACD,CAAA,CAAA,CAAI,CAACC,CAAAA,CAAOC,CAAUC,CAAAA,CAAQ,CAAIL,CAAAA,CAAAA,CAAMC,CAAG,CAG3C,CAAA,CAAA,CAAA,CAAII,CAAYhD,CAAAA,CAAAA,CAAAA,CAAwB,CACtC,CAAA,CAAE4C,CACF,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACF,CAGAD,CAAMC,CAAAA,CAAG,CAAE,CAAA,CAAC,CAAKvD,CAAAA,CAAAA,CAAAA,CACjB,CAAEsD,CAAAA,CAAAA,CAAMC,CAAG,CAAE,CAAA,CAAC,CAGd,CAAA,CAAA,CAAA,CAAA,CAAIK,CAAS3B,CAAAA,CAAAA,CAAMwB,CAAK,CAAA,CAAEC,CAAW5D,CAAAA,CAAgB,CACrD,CAAA,CAAA,CAAA,CAAI8D,CAAW9C,CAAAA,CAAAA,CAAAA,CAAAA,CACb,CAIF,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM+C,EAAa5B,CAAMwB,CAAAA,CAAK,CAAEG,CAAAA,CAAAA,CAAStD,CAAgB,CAAA,CACrDmD,CAAUI,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACZD,EAAS3B,CAAMwB,CAAAA,CAAK,CAAEG,CAAAA,CAAAA,CAASzD,CAAiB,CAAA,CAChDsD,CAAQI,CAAAA,CAAAA,CAAAA,CAIVtC,EAAIgC,CAAG,CAAA,CAAII,CAAW9F,CAAAA,CAAAA,CACtByF,CAAM,CAAA,CAAA,CAAEC,CAAG,CAAA,CAAI,CAACE,CAAAA,CAAOG,CAASlD,CAAAA,CAAAA,CAAwB,CAAC,CAAA,CAGzD,CAAMoD,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAa7B,EAAMwB,CAAK,CAAA,CAAEG,CAASpD,CAAAA,CAAmB,CACxDsD,CAAAA,CAAAA,CAAAA,CAAAA,CAAehD,CAEb0C,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACFL,EAAO,CAAMC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAS,CAExBI,CAAAA,CAAAA,CAAO,CACPH,CAAAA,CAAAA,CAAAA,CAAWF,CAAQ5B,CAAAA,CAAAA,CAAKgC,EAAKO,CAAU,CAAA,CAE3C,CAASP,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAO,CAClB,CAAA,CCvMgB,CAAAQ,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAaC,CAA4B,CAAA,CACvD,CAAMC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAS,CAAIC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAOF,CAAU,CAAA,CACpC,OAAAC,CAAO,CAAA,CAAA,CAAA,CAAG,CAAUE,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAQ,CAC1B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMA,CACR,CAAC,EACDF,CAAO,CAAA,CAAA,CAAA,CAAG,CAAiBE,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAQ,CACjC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMA,CACR,CAAC,EACDF,CAAO,CAAA,CAAA,CAAA,CAAG,CAASG,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAS,CAC1B,CAAA,CAAA,CAAIA,CAAO,CAAA,CAAA,CAAA,CAAKA,CAAO,CAAA,CAAA,CACrB,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAUH,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,qBAAqBG,CAAI,CAAA,CAAE,CAExE,CAAC,CACMH,CAAAA,CACT,CAUgB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAI,EAAeJ,CAAgBK,CAAAA,CAAAA,CAAwB,CACrE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAcC,CAAY,CAAA,CAAA,CACnCN,EAAO,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAWM,CAAO,CAAA,CAC9BN,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAYK,CAAG,CACxB,CAAC,CACH,CCnBsB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAE,CACpB3F,CAAAA,CAAAA,CAAAA,CACAmF,CACAS,CAAAA,CAAAA,CACAC,EAAU,CACK,CAAA,CAAA,CAEfD,CAAajG,CAAAA,CAAAA,CAAMiG,CAAYnG,CAAAA,CAAAA,CAAAA,CAAaC,CAAW,CAAA,CAAA,CAGvD,MAAMe,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMV,CACnBC,CAAAA,CAAAA,CAAAA,CACA4F,CACAjH,CAAAA,CAAAA,CACAW,CACF,CAAA,CAAA,CAGAsG,EAAanF,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAGpB,CAAMqF,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAS,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAmBrH,CAAemH,CAAAA,CAAAA,CAAa,CAAM,CAAA,CAAA,CAAC,CACnEG,CAAAA,CAAAA,CAAO,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAWD,CAAM,CAAA,CAC5BE,EAAQ,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAWF,CAAQ,CAAA,CAAC,CAChCG,CAAAA,CAAAA,CAAS,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAYH,EAAQ,CAAC,CAAA,CAClCI,CAAO,CAAA,CAAA,CAAA,CAAA,CAAI,CAAaJ,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAQ,CAAC,CAAA,CACjC1C,EAAsB,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMwC,CAAU,CAAA,CAG1CO,CAAU,CAAA,CAAA,CAAA,CAAA,CAAI,CAAcP,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAU,CAC5C,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS1C,CAAI,CAAA,CAAA,CAAGA,CAAI0C,CAAAA,CAAAA,CAAY,CAAE1C,CAAAA,CAAAA,CAChCiD,EAAQjD,CAAC,CAAA,CAAIgC,CAAaC,CAAAA,CAAAA,CAAU,CAItC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMiB,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAI,MAAwBR,CAAU,CAAA,CACpD,CAAS1C,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAI,CAAGA,CAAAA,CAAAA,CAAI0C,CAAY,CAAA,CAAA,CAAE1C,EAChCkD,CAAMlD,CAAAA,CAAC,CAAIsC,CAAAA,CAAAA,CAAsCW,CAAQjD,CAAAA,CAAC,CAAG,CAAA,CAC3D,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACN,CAAA+C,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACA,CAAKxF,CAAAA,CAAAA,CAAAA,CAAAA,CAAOyC,CAAC,CAAA,CAAE,CAAC,CAChB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAlD,CACA,CAAA,CAAA,CAAA,CAAIkD,CACJ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA8C,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAD,EACA,CAAOtF,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAOyC,CAAC,CAAA,CAAE,CAAC,CAAA,CAClB,CAAAgD,CAAAA,CAAAA,CAAAA,CAAAA,CACF,CAAC,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMtF,CAAQ,CAAA,CAAA,CACfwC,CAAMxC,CAAAA,CAAAA,CAAI,CAAE,CAAA,CAAA,CAAIA,CAAI,CAAA,CAAA,CAAA,CAAA,CACtB,CAAC,CAAA,CAIH,CAASsC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAIkD,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,EAAGlD,CAAI,CAAA,CAAA,CAAG,CAAEA,CAAAA,CAAAA,CAAG,CACzC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMmD,CAAKnD,CAAAA,CAAAA,CAAI,GAAM,CACfoD,CAAAA,CAAAA,CAAIpD,CACVkD,CAAAA,CAAAA,CAAMC,CAAC,CAAA,CAAID,CAAMC,CAAAA,CAAC,EACf,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMD,CAAME,CAAAA,CAAC,CAAC,CAAA,CACnB,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACJd,CAAkCW,CAAAA,CAAAA,CAAQE,CAAC,CAAA,CAAG,CAC5C,CAAA,CAAA,CAAA,CAAA,CAAM,CACN,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAA,EACA,CAAAC,CAAAA,CAAAA,CACA,CAAAL,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACA,CAAAD,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACA,CAAAD,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACA,KAAAG,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA9C,CACF,CAAC,CACH,CAAA,CACC,CAAMxC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAQ,CACbwC,CAAMxC,CAAAA,CAAAA,CAAI,CAAE,CAAA,CAAA,CAAIA,CAAI,CAAA,CAAA,CAAA,CAAA,CACtB,CAAC,CACL,CAGA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAASsC,CAAI,CAAA,CAAA,CAAGA,CAAI0C,CAAAA,CAAAA,CAAY,CAAE1C,CAAAA,CAAAA,CAChCkD,EAAMlD,CAAC,CAAA,CAAIkD,CAAMlD,CAAAA,CAAC,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAMiD,CAAAA,CAAAA,CAAAA,CAAAA,CAAQjD,CAAC,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,CAAA,CAIvD,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAIkD,CAAAA,CAAAA,CAAAA,CAAK,EAGvB,CAAMG,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAMC,CAAkBX,CAAAA,CAAAA,CAAS,CACrC,CAAA,CAAA,CAAIA,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAI,CAAA,CAAA,CAAI,CAC7B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CACP,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAezG,CACjB,CAAA,CAAC,EACKoB,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAY9B,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAoB,CACtD6H,CAAAA,CAAAA,CAAI,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,EACbnC,CAAMhB,CAAAA,CAAAA,CAAAA,CAAO5C,CAAQ,CAAA,CAAA,CAAG+F,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAME,CAAY,CAAA,CAC/CF,EAAI,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAK,CAEb,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAASE,CACPnC,CAAAA,CAAAA,CACAoC,CACAC,CAAAA,CAAAA,CACAC,CACM,CAAA,CACN,CAAMC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAM,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMX,CAAKU,CAAAA,CAAAA,CAAAA,CAAM,CAAC,CAAA,CAAIX,CAAOW,CAAAA,CAAAA,CAAAA,CAAM,CAAC,CAAC,CACtDtC,CAAAA,CAAAA,CAAO,CAAMoC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAK,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAGC,CAAAA,CAAO,CAAC,CAAA,CAC9CrC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAG,CAAA,CAAA,CAAA,CAChBA,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAOyB,CAAKa,CAAAA,CAAAA,CAAAA,CAAM,CAAC,CAAA,CAAI,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAC,CAAC,CAC5CtC,CAAAA,CAAAA,CAAO,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAChBA,CAAAA,CAAAA,CAAO,CAAOuC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAM,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAC,CAAC,CAClCvC,CAAAA,CAAAA,CAAO,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAChBA,CAAAA,CAAAA,CAAO,CAAO0B,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAMY,CAAM,CAAA,CAAA,CAAC,CAAI,CAAA,CAAA,CAAA,CAAA,CAAI,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAC,CAC/C,CACF,CChHsB,CAAAjB,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAI,CACxB,CAAA,CAAA,CAAA,CAAAhF,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAX,CACA,CAAA,CAAA,CAAA,CAAA+C,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAArC,CAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAuF,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAD,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAD,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAG,CACF,CAAA,CAA6C,CAE3C,CAAA,CAAA,CAAIxF,CAASC,CAAAA,CAAAA,CAAAA,CACX,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAoB,CAAAoC,CAAAA,CAAAA,CAAAA,CAAI,CAAMD,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAWC,CAAI,CAAA,CAAC,CAAE,CAAA,CAIjE,CAAIN,CAAAA,CAAAA,CAAAA,CAAAA,CAAOK,CAAWC,CAAAA,CAAE,CACpB+D,CAAAA,CAAAA,CAAW/D,CAAKtE,CAAAA,CAAAA,CAAe,CACnC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM+B,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAY7B,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAa,EAGzC2F,CAASyC,CAAAA,CAAAA,CAAiB/G,CAAU,CAAA,CACxC,CAAAU,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACA,CAAKC,CAAAA,CAAAA,CAAAA,CAAAA,CAAM,CACX,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAeG,CAAiBH,CAAAA,CAAAA,CAAAA,CAAMD,CAAK,CAC7C,CAAC,CAAA,CAGD,CAAIsG,CAAAA,CAAAA,CAAAA,CAAAA,CAAO,CACPC,CAAAA,CAAAA,CAAQ,CACRC,CAAAA,CAAAA,CACJ,CAAiBC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAS7C,CAAQ,CAAA,CAEhC,CAAM8C,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAID,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAChB,CAASjE,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAI,CAAGA,CAAAA,CAAAA,CAAIkE,CAAG,CAAA,CAAA,CAAElE,CACvB,CAAA,CAAA,CAAA,CAAIiE,CAAMjE,CAAAA,CAAC,CAAMpE,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAEfmI,CAAQD,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACCG,CAAMjE,CAAAA,CAAC,CAAMrE,CAAAA,CAAAA,CAAAA,CAAAA,CAEtB2B,CAAOwG,CAAAA,CAAAA,CAAAA,CAAM,CAAIG,CAAAA,CAAAA,CAAMjE,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CACnB,CAEL,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMmE,CAAQC,CAAAA,CAAAA,CAAAA,CAAY9G,CAAQyG,CAAAA,CAAAA,CAAOD,CAAI,CAAA,CAC7CA,CAAO,CAAA,CAAA,CAEP,CAACvE,CAAAA,CAAMyE,CAAI,CAAA,CAAI1E,CAAIC,CAAAA,CAAAA,CAAAA,CAAMjC,CAAQ,CAAA,CAAA,CAAGyG,CAAK,CAAA,CAErCxE,CAAKyE,CAAAA,CAAAA,CAAOvF,CAAmB,CAAA,CAAA,CAAA,CAAMM,CAEvCsF,CAAAA,CAAAA,CAAc9E,CAAKyE,CAAAA,CAAAA,CAAOvF,CAAmB,CAAA,CAAG0F,CAAK,CAAA,CAAA,CAGrD5E,CAAKyE,CAAAA,CAAAA,CAAOvF,CAAmB,CAAA,CAAImF,CACnCU,CAAAA,CAAAA,CAAWV,CAAYO,CAAAA,CAAAA,CAAAA,CAAK,CAEhC,CAAA,CAEJ,CAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAASG,CAAW7E,CAAAA,CAAAA,CAAe8E,CAAoB,CAAA,CACrD1B,CAAKpD,CAAAA,CAAAA,CAAAA,CAAS,CAAC,CAAA,CAAI8E,CACnBzB,CAAAA,CAAAA,CAAMrD,CAAS,CAAA,CAAA,CAAC,CAAI8E,CAAAA,CAAAA,CACpBxB,CAAOtD,CAAAA,CAAAA,CAAAA,CAAS,CAAC,CAAA,CAAI,CACrBuD,CAAAA,CAAAA,CAAKvD,CAAS,CAAA,CAAA,CAAC,CAAI8E,CAAAA,CACrB,CAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAASF,CAAc5E,CAAAA,CAAAA,CAAe8E,CAAoB,CAAA,CACxD9E,IAAU,CACVoD,CAAAA,CAAAA,CAAKpD,CAAK,CAAA,CAAIoD,CAAKpD,CAAAA,CAAK,CAAK8E,CAAAA,CAAAA,CAAAA,CAAO1B,CAAKpD,CAAAA,CAAK,CAAI8E,CAAAA,CAAAA,CAClDzB,CAAMrD,CAAAA,CAAK,CAAIqD,CAAAA,CAAAA,CAAMrD,CAAK,CAAA,CAAA,CAAK8E,CAAOzB,CAAAA,CAAAA,CAAMrD,CAAK,CAAA,CAAI8E,CACrD,CAAA,CAAA,CAAExB,CAAOtD,CAAAA,CAAAA,CAAAA,CAAS,CAAC,CAAA,CACnBuD,CAAKvD,CAAAA,CAAAA,CAAAA,CAAS,CAAC,CAAA,CAAA,CAAK8E,CACtB,CAEA,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAoB,CAAA1E,CAAAA,CAAAA,CAAAA,CAAI,CAAAN,CAAAA,CAAAA,CAAAA,CAAAA,CAAK,CAC9C,CAEO,CAAS6E,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAYhB,CAAWzG,CAAAA,CAAAA,CAAaC,CAAqB,CAAA,CACvE,CAAIwG,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAEzG,CAAG,CAAA,CAAA,CAAA,CAAMjB,CACb,CAAA,CAAA,CAAA,CAAA,CAAEiB,CACKA,CAAAA,CAAAA,CAAM,CAAIC,CAAAA,CAAAA,CACb,CAAE,CAAA,CAAA,CAAA,CAAKwG,CAAEzG,CAAAA,CAAG,CAAIyG,CAAAA,CAAAA,CAAEzG,CAAM,CAAA,CAAC,CAAIN,CAAAA,CAAAA,CAAAA,CAC7B,CAAE,CAAA,CAAA,CAAA,CAAA,CAAM+G,CAAEzG,CAAAA,CAAG,CAAI,CAAA,CAAA,CAAA,CAAKyG,CAAEzG,CAAAA,CAAAA,CAAM,CAAC,CAAA,CAAIyG,CAAEzG,CAAAA,CAAAA,CAAM,CAAC,CAAA,CAAIL,CAE/CK,CAAAA,CAAAA,CAAAA,CAAAA,CAAM,CAAIC,CAAAA,CAAAA,CACb,CAAKwG,CAAAA,CAAAA,CAAAA,CAAEzG,CAAG,CAAA,CAAIyG,CAAEzG,CAAAA,CAAAA,CAAM,CAAC,CAAA,CAAIN,CAC3B,CAAA,CAAA,CAAA,CAAA,CAAM+G,CAAEzG,CAAAA,CAAG,CAAI,CAAA,CAAA,CAAA,CAAKyG,CAAEzG,CAAAA,CAAAA,CAAM,CAAC,CAAA,CAAIyG,CAAEzG,CAAAA,CAAAA,CAAM,CAAC,CAAA,CAAIL,CACpD,CAEgB,CAAAkI,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAM,CACpB,CAAA,CAAArB,CACA,CAAA,CAAA,CAAAC,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAlD,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA6C,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAD,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAD,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAG,CACF,CAAgC,CAAA,CAC9B/C,CAAUC,CAAAA,CAAAA,CAAAA,CAAOiD,CAAGC,CAAAA,CAAAA,CAAGqB,CAAa,CAAA,CACpC,CAASA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAchE,CAAYC,CAAAA,CAAAA,CAAkB,CACnDD,CAAAA,CAAAA,CAAAA,CAAO,CACPC,CAAAA,CAAAA,CAAAA,CAAAA,CAAO,CACPmC,CAAAA,CAAAA,CAAKpC,CAAE,CAAA,CAAI,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAIoC,CAAKpC,CAAAA,CAAE,CAAGoC,CAAAA,CAAAA,CAAKnC,CAAE,CAAC,CACtCoC,CAAAA,CAAAA,CAAMrC,CAAE,CAAA,CAAI,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAIqC,CAAMrC,CAAAA,CAAE,CAAGqC,CAAAA,CAAAA,CAAMpC,CAAE,CAAC,CACzCqC,CAAAA,CAAAA,CAAOtC,CAAM,CAAA,CAAA,CAAC,CAAKsC,CAAAA,CAAAA,CAAAA,CAAOrC,CAAM,CAAA,CAAA,CAAC,CACjCsC,CAAAA,CAAAA,CAAKvC,CAAM,CAAA,CAAA,CAAC,CAAKuC,CAAAA,CAAAA,CAAAA,CAAKtC,CAAM,CAAA,CAAA,CAAC,CAC/B,CACA,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAkB,CAAIyC,CAAAA,CAAAA,CAAAA,CAAG,KAAMjD,CAAMiD,CAAAA,CAAC,CAAE,CACzD,CCpHA,CAAA,CAAA,CAAIuB,CAAc,CAAA,CAChB,CAAMzC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAa0C,CAAc,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAY,CAAG,CAAA,CAAA,CAAA,CAChDC,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAG3C,CAAAA,CAAAA,CAAY4C,CAAsB,CAAA,CAAA,CAC7D,CAAA,CAAA,CAAA,CAAA,CAAA,CACEC,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAY,CAAW,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAOC,CAAiB,CAAA,CAAA,CACzD,CAAIA,CAAAA,CAAAA,CAAAA,CAAI,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAmB,CAClC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMrH,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMsH,CAAUD,CAAAA,CAAAA,CAAqB,CACjDD,CAAAA,CAAAA,CAAY,CAAYpH,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAG,CAC7B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAWqH,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAiB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACvC,CAAMrH,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAM8G,CAAMO,CAAAA,CAAAA,CAAmB,CACrCD,CAAAA,CAAAA,CAAY,CAAYpH,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAG,CAC7B,CAAA,CAAA,CAAA,CAAA,CACE,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAsB,CAE1C,CAAC,CAAA,CAAA;"} \ No newline at end of file +{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN } from \"./utf8\";\n\n// Configurable constants\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 524288; // 2 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Internal trie pointer\n\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Cross-trie pointer (aka redirect)\n\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a null / undefined trie element.\n */\nexport const TRIE_NULL = 0;\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_PTR_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_XPTR_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach and initialize node\n trie[index + TRIE_PTR_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_PTR_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_PTR_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Add new redirect\n tries[at][li + TRIE_XPTR_ID_IDX] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_B0_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n mergeLeft(tries, a, b, mergeStations);\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n return { type: \"merge_response\", id: a, trie: tries[a] };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n const res = await runWorker(msg as ProcessRequest);\n parentPort!.postMessage(res);\n } else if (msg.type === \"merge_request\") {\n const res = merge(msg as MergeRequest);\n parentPort!.postMessage(res);\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_B0_MIN","UTF8_B0_2B_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","CHAR_ZERO_11","CHAR_ZERO_111","MIN_WORKERS","MAX_WORKERS","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_IDX","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_IDX","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","stations","createReadStream","bufI","tempI","leaf","chunk","N","tempV","parseDouble","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/eslint.config.js b/src/main/nodejs/havelessbemore/eslint.config.js index a9a081b..917eec7 100644 --- a/src/main/nodejs/havelessbemore/eslint.config.js +++ b/src/main/nodejs/havelessbemore/eslint.config.js @@ -1,20 +1,10 @@ import eslint from "@eslint/js"; -import globals from "globals"; import prettierConfig from "eslint-config-prettier"; import tseslint from "typescript-eslint"; /** @type {import('@typescript-eslint/utils').TSESLint.FlatConfig.ConfigArray} */ export default tseslint.config( - { - ignores: ["dist/", "docs/"], - languageOptions: { - globals: { - ...globals.browser, - ...globals.node, - ...globals.worker, - }, - }, - }, + { ignores: ["dist"] }, eslint.configs.recommended, ...tseslint.configs.recommended, ...tseslint.configs.stylistic, diff --git a/src/main/nodejs/havelessbemore/package.json b/src/main/nodejs/havelessbemore/package.json index 5a46854..11f9750 100644 --- a/src/main/nodejs/havelessbemore/package.json +++ b/src/main/nodejs/havelessbemore/package.json @@ -23,7 +23,7 @@ "bench": "tsx ./benchmarks/bench.ts ../../../../measurements.txt", "build": "rimraf dist && tsc && rollup -c --configPlugin typescript", "format": "prettier . --write", - "lint": "eslint" + "lint": "eslint ." }, "devDependencies": { "@rollup/plugin-typescript": "^11.1.6", diff --git a/src/main/nodejs/havelessbemore/src/main.ts b/src/main/nodejs/havelessbemore/src/main.ts index 30930a9..a54ab7d 100644 --- a/src/main/nodejs/havelessbemore/src/main.ts +++ b/src/main/nodejs/havelessbemore/src/main.ts @@ -43,7 +43,7 @@ export async function run( const maxes = new Int16Array(valBuf, 2); const counts = new Uint32Array(valBuf, 4); const sums = new Float64Array(valBuf, 8); - const tries: Int32Array[] = new Array(maxWorkers); + const tries = new Array(maxWorkers); // Create workers const workers = new Array(maxWorkers); diff --git a/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts b/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts index cf4d3c2..280b965 100644 --- a/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts +++ b/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts @@ -80,6 +80,7 @@ export function mergeLeft( do { const Q = queue.length; for (let q = 0; q < Q; ++q) { + // eslint-disable-next-line prefer-const let [at, ai, bt, bi] = queue[q]; // If right value is not null @@ -160,12 +161,13 @@ export function print( valueIndex: number, ) => void, ): void { - const stack: [number, number, number][] = new Array(key.length + 1); + const stack = new Array<[number, number, number]>(key.length + 1); stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0]; let top = 0; let tail = false; do { + // eslint-disable-next-line prefer-const let [trieI, childPtr, numChild] = stack[top]; // Check if end of children array From 473bbd763bba8b5045660aa548f02099980b236e Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Thu, 23 May 2024 12:50:26 -0400 Subject: [PATCH 23/69] Add get() utf8trie function, Fix bug in mergeLeft() function where redirect was being allocated and initialized but not attached to the parent node --- src/main/nodejs/havelessbemore/dist/index.cjs | 4 +- .../nodejs/havelessbemore/dist/index.cjs.map | 2 +- src/main/nodejs/havelessbemore/dist/index.mjs | 4 +- .../nodejs/havelessbemore/dist/index.mjs.map | 2 +- src/main/nodejs/havelessbemore/src/main.ts | 8 +- .../havelessbemore/src/types/mergeResponse.ts | 4 +- .../havelessbemore/src/utils/utf8Trie.ts | 95 ++++++++++++------- src/main/nodejs/havelessbemore/src/worker.ts | 4 +- 8 files changed, 76 insertions(+), 47 deletions(-) diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs b/src/main/nodejs/havelessbemore/dist/index.cjs index 2d45441..e9c4c03 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs +++ b/src/main/nodejs/havelessbemore/dist/index.cjs @@ -24,6 +24,6 @@ * SOFTWARE. */ -"use strict";var Y=require("node:os"),J=require("node:url"),X=require("node:worker_threads"),U=require("node:fs"),Q=require("fs/promises"),ee=require("worker_threads"),P=typeof document<"u"?document.currentScript:null;const x=1e4,te=100,W=107,re=45,C=10,ne=59,q=48,k=32,se=192,v=16384,ae=1048576,oe=1048576,ie=152e-6,_e=v,F=11*q,B=111*q,ce=1,ue=512;function b(e,t,r){return e>t?e<=r?e:r:t}async function Ee(e,t,r,l=0){const a=await Q.open(e);try{const i=(await a.stat()).size,f=Math.max(l,Math.floor(i/t)),s=Buffer.allocUnsafe(r),o=[];let _=0;for(let E=f;E=0&&ue.length&&(e=j(e,i+L)),e[g]+=L,e[a+p]=i,e[i+D]=e[G]),a=i}return[e,a]}function V(e=0,t=le){t=Math.max($,t);const r=new Int32Array(new SharedArrayBuffer(t<<2));return r[g]=$,r[G]=e,r}function j(e,t=0){const r=e[g];t=Math.max(t,Math.ceil(r*Ie));const l=new Int32Array(new SharedArrayBuffer(t<<2));for(let a=0;ae[s].length&&(e[s]=j(e[s],h+S)),e[s][g]+=S,e[s][h+Me]=T,e[s][h+H]=I;else{const n=e[s][h+D];s!==n&&(o=e[s][h+H]),a.push([n,h,T,I])}o+=m,E+=m}}a.splice(0,i)}while(a.length>0)}function De(e,t,r,l,a="",i){const f=new Array(t.length+1);f[0]=[r,N+y,0];let s=0,o=!1;do{let[_,E,M]=f[s];if(M>=K){--s;continue}f[s][1]+=m,++f[s][2];let u=e[_][E+p];if(u===w)continue;const I=e[_][u+D];_!==I&&(u=e[_][u+H],_=I),t[s]=M+k,f[++s]=[_,u+y,0];const T=e[_][u+A];T!==w&&(o&&l.write(a),o=!0,i(l,t,s,T))}while(s>=0)}function ye(e){const t=new ee.Worker(e);return t.on("error",r=>{throw r}),t.on("messageerror",r=>{throw r}),t.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${t.threadId} exited with code ${r}`)}),t}function z(e,t){return new Promise(r=>{e.once("message",r),e.postMessage(t)})}async function Ne(e,t,r,l=""){r=b(r,ce,ue);const a=await Ee(e,r,W,_e);r=a.length;const i=new SharedArrayBuffer(x*r+1<<4),f=new Int16Array(i),s=new Int16Array(i,2),o=new Uint32Array(i,4),_=new Float64Array(i,8),E=new Array(r),M=new Array(r);for(let n=0;n{E[c.id]=c.trie});for(let n=u.length-1;n>0;--n){const c=n-1>>1,R=n;u[c]=u[c].then(()=>u[R]).then(()=>z(M[c],{type:"merge_request",a:c,b:R,counts:o,maxes:s,mins:f,sums:_,tries:E})).then(d=>{E[d.id]=d.trie})}for(let n=0;nM[n].terminate());await Promise.all(u);const I=U.createWriteStream(l,{fd:l.length<1?1:void 0,flags:"a",highWaterMark:oe}),T=Buffer.allocUnsafe(te);I.write("{"),De(E,T,0,I,", ",h),I.end(`} -`);function h(n,c,R,d){const O=Math.round(_[d<<1]/o[d<<2]);n.write(c.toString("utf8",0,R)),n.write("="),n.write((f[d<<3]/10).toFixed(1)),n.write("/"),n.write((O/10).toFixed(1)),n.write("/"),n.write((s[d<<3]/10).toFixed(1))}}async function Oe({end:e,filePath:t,id:r,start:l,counts:a,maxes:i,mins:f,sums:s}){if(l>=e)return{type:"process_response",id:r,trie:V(r,0)};let o=V(r),_=r*x+1;const E=Buffer.allocUnsafe(W),M=U.createReadStream(t,{start:l,end:e-1,highWaterMark:fe(e-l)});let u=0,I=0,T;for await(const c of M){const R=c.length;for(let d=0;d=R?i[c]:R,++a[c>>1],s[c>>2]+=R}return{type:"process_response",id:r,trie:o}}function Xe(e,t,r){return e[t]===re?(++t,t+4>r?-(10*e[t]+e[t+2]-F):-(100*e[t]+10*e[t+1]+e[t+3]-B)):t+4>r?10*e[t]+e[t+2]-F:100*e[t]+10*e[t+1]+e[t+3]-B}function He({a:e,b:t,tries:r,counts:l,maxes:a,mins:i,sums:f}){pe(r,e,t,s);function s(o,_){o<<=3,_<<=3,i[o]=Math.min(i[o],i[_]),a[o]=Math.max(a[o],a[_]),l[o>>1]+=l[_>>1],f[o>>2]+=f[_>>2]}return{type:"merge_response",id:e,trie:r[e]}}if(X.isMainThread){const e=J.fileURLToPath(typeof document>"u"?require("url").pathToFileURL(__filename).href:P&&P.src||new URL("index.cjs",document.baseURI).href);Ne(process.argv[2],e,Y.availableParallelism())}else X.parentPort.addListener("message",async e=>{if(e.type==="process_request"){const t=await Oe(e);X.parentPort.postMessage(t)}else if(e.type==="merge_request"){const t=He(e);X.parentPort.postMessage(t)}else throw new Error("Unknown message type")}); +"use strict";var Y=require("node:os"),J=require("node:url"),X=require("node:worker_threads"),U=require("node:fs"),Q=require("fs/promises"),ee=require("worker_threads"),P=typeof document<"u"?document.currentScript:null;const x=1e4,te=100,W=107,re=45,C=10,ne=59,q=48,k=32,se=192,v=16384,ae=1048576,oe=1048576,ie=152e-6,_e=v,F=11*q,b=111*q,ce=1,ue=512;function B(e,t,r){return e>t?e<=r?e:r:t}async function fe(e,t,r,I=0){const _=await Q.open(e);try{const a=(await _.stat()).size,f=Math.max(I,Math.floor(a/t)),u=Buffer.allocUnsafe(r),s=[];let o=0;for(let E=f;E=0&&ce.length&&(e=j(e,a+H)),e[y]+=H,e[_+p]=a,e[a+D]=e[G]),_=a}return[e,_]}function V(e=0,t=Ie){t=Math.max($,t);const r=new Int32Array(new SharedArrayBuffer(t<<2));return r[y]=$,r[G]=e,r}function j(e,t=0){const r=e[y];t=Math.max(t,Math.ceil(r*Re));const I=new Int32Array(new SharedArrayBuffer(t<<2));for(let _=0;_e[s].length&&(e[s]=j(e[s],n+L),_.add(s)),e[s][y]+=L,e[s][o+p]=n,e[s][n+Me]=w,e[s][n+S]=R;else{const i=e[s][n+D];s!==i&&(n=e[s][n+S]),a.push([i,n,w,R])}}o+=g,l+=g}}a.splice(0,f)}while(a.length>0);return Array.from(_)}function ge(e,t,r,I,_="",a){const f=new Array(t.length+1);f[0]=[r,O+N,0];let u=0,s=!1;do{let[o,E,l]=f[u];if(l>=K){--u;continue}f[u][1]+=g,++f[u][2];let c=e[o][E+p];if(c===h)continue;const d=e[o][c+D];o!==d&&(c=e[o][c+S],o=d),t[u]=l+k,f[++u]=[o,c+N,0];const R=e[o][c+A];R!==h&&(s&&I.write(_),s=!0,a(I,t,u,R))}while(u>=0)}function De(e){const t=new ee.Worker(e);return t.on("error",r=>{throw r}),t.on("messageerror",r=>{throw r}),t.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${t.threadId} exited with code ${r}`)}),t}function z(e,t){return new Promise(r=>{e.once("message",r),e.postMessage(t)})}async function Ne(e,t,r,I=""){r=B(r,ce,ue);const _=await fe(e,r,W,_e);r=_.length;const a=new SharedArrayBuffer(x*r+1<<4),f=new Int16Array(a),u=new Int16Array(a,2),s=new Uint32Array(a,4),o=new Float64Array(a,8),E=new Array(r),l=new Array(r);for(let n=0;n{E[i.id]=i.trie});for(let n=c.length-1;n>0;--n){const i=n-1>>1,M=n;c[i]=c[i].then(()=>c[M]).then(()=>z(l[i],{type:"merge_request",a:i,b:M,counts:s,maxes:u,mins:f,sums:o,tries:E})).then(T=>{for(const m of T.ids)E[m]=T.tries[m]})}for(let n=0;nl[n].terminate());await Promise.all(c);const d=U.createWriteStream(I,{fd:I.length<1?1:void 0,flags:"a",highWaterMark:oe}),R=Buffer.allocUnsafe(te);d.write("{"),ge(E,R,0,d,", ",w),d.end(`} +`);function w(n,i,M,T){const m=Math.round(o[T<<1]/s[T<<2]);n.write(i.toString("utf8",0,M)),n.write("="),n.write((f[T<<3]/10).toFixed(1)),n.write("/"),n.write((m/10).toFixed(1)),n.write("/"),n.write((u[T<<3]/10).toFixed(1))}}async function Oe({end:e,filePath:t,id:r,start:I,counts:_,maxes:a,mins:f,sums:u}){if(I>=e)return{type:"process_response",id:r,trie:V(r,0)};let s=V(r),o=r*x+1;const E=Buffer.allocUnsafe(W),l=U.createReadStream(t,{start:I,end:e-1,highWaterMark:Ee(e-I)});let c=0,d=0,R;for await(const i of l){const M=i.length;for(let T=0;T=M?a[i]:M,++_[i>>1],u[i>>2]+=M}return{type:"process_response",id:r,trie:s}}function Xe(e,t,r){return e[t]===re?(++t,t+4>r?-(10*e[t]+e[t+2]-F):-(100*e[t]+10*e[t+1]+e[t+3]-b)):t+4>r?10*e[t]+e[t+2]-F:100*e[t]+10*e[t+1]+e[t+3]-b}function Se({a:e,b:t,tries:r,counts:I,maxes:_,mins:a,sums:f}){function u(s,o){s<<=3,o<<=3,a[s]=Math.min(a[s],a[o]),_[s]=Math.max(_[s],_[o]),I[s>>1]+=I[o>>1],f[s>>2]+=f[o>>2]}return{type:"merge_response",ids:ye(r,e,t,u),tries:r}}if(X.isMainThread){const e=J.fileURLToPath(typeof document>"u"?require("url").pathToFileURL(__filename).href:P&&P.src||new URL("index.cjs",document.baseURI).href);Ne(process.argv[2],e,Y.availableParallelism())}else X.parentPort.addListener("message",async e=>{if(e.type==="process_request"){const t=await Oe(e);X.parentPort.postMessage(t)}else if(e.type==="merge_request"){const t=Se(e);X.parentPort.postMessage(t)}else throw new Error("Unknown message type")}); //# sourceMappingURL=index.cjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs.map b/src/main/nodejs/havelessbemore/dist/index.cjs.map index a420ee2..e26d934 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.cjs.map @@ -1 +1 @@ -{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN } from \"./utf8\";\n\n// Configurable constants\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 524288; // 2 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Internal trie pointer\n\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Cross-trie pointer (aka redirect)\n\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a null / undefined trie element.\n */\nexport const TRIE_NULL = 0;\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_PTR_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_XPTR_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach and initialize node\n trie[index + TRIE_PTR_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_PTR_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_PTR_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Add new redirect\n tries[at][li + TRIE_XPTR_ID_IDX] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_B0_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n mergeLeft(tries, a, b, mergeStations);\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n return { type: \"merge_response\", id: a, trie: tries[a] };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n const res = await runWorker(msg as ProcessRequest);\n parentPort!.postMessage(res);\n } else if (msg.type === \"merge_request\") {\n const res = merge(msg as MergeRequest);\n parentPort!.postMessage(res);\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_B0_MIN","UTF8_B0_2B_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","CHAR_ZERO_11","CHAR_ZERO_111","MIN_WORKERS","MAX_WORKERS","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_IDX","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_IDX","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","stations","createReadStream","bufI","tempI","leaf","chunk","N","tempV","parseDouble","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","_documentCurrentScript","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN } from \"./utf8\";\n\n// Configurable constants\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 524288; // 2 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Internal trie pointer\n\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Cross-trie pointer (aka redirect)\n\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a null / undefined trie element.\n */\nexport const TRIE_NULL = 0;\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_PTR_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_XPTR_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index + TRIE_PTR_IDX_IDX] = child;\n // Initialize node\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node + TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN);\n let child = tries[trie][ptr + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TRIE_NODE_ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_PTR_IDX_IDX];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_PTR_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai + TRIE_PTR_IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TRIE_XPTR_ID_IDX] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_B0_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { type: \"merge_response\", ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n const res = await runWorker(msg as ProcessRequest);\n parentPort!.postMessage(res);\n } else if (msg.type === \"merge_request\") {\n const res = merge(msg as MergeRequest);\n parentPort!.postMessage(res);\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_B0_MIN","UTF8_B0_2B_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","CHAR_ZERO_11","CHAR_ZERO_111","MIN_WORKERS","MAX_WORKERS","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_IDX","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_IDX","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","stations","createReadStream","bufI","tempI","leaf","chunk","N","tempV","parseDouble","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","_documentCurrentScript","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index 7561f4d..57b7074 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -24,6 +24,6 @@ * SOFTWARE. */ -import{availableParallelism as z}from"node:os";import{fileURLToPath as Y}from"node:url";import{isMainThread as j,parentPort as L}from"node:worker_threads";import{createWriteStream as J,createReadStream as Q}from"node:fs";import{open as ee}from"fs/promises";import{Worker as te}from"worker_threads";const x=1e4,re=100,P=107,ne=45,U=10,se=59,W=48,C=32,oe=192,B=16384,ae=1048576,ie=1048576,_e=152e-6,ce=B,F=11*W,k=111*W,Ee=1,fe=512;function K(e,t,r){return e>t?e<=r?e:r:t}async function Ie(e,t,r,l=0){const o=await ee(e);try{const i=(await o.stat()).size,I=Math.max(l,Math.floor(i/t)),s=Buffer.allocUnsafe(r),a=[];let _=0;for(let f=I;f=0&&Ee.length&&(e=$(e,i+H)),e[g]+=H,e[o+p]=i,e[i+D]=e[G]),o=i}return[e,o]}function v(e=0,t=ue){t=Math.max(q,t);const r=new Int32Array(new SharedArrayBuffer(t<<2));return r[g]=q,r[G]=e,r}function $(e,t=0){const r=e[g];t=Math.max(t,Math.ceil(r*Re));const l=new Int32Array(new SharedArrayBuffer(t<<2));for(let o=0;oe[s].length&&(e[s]=$(e[s],m+S)),e[s][g]+=S,e[s][m+Te]=T,e[s][m+X]=u;else{const n=e[s][m+D];s!==n&&(a=e[s][m+X]),o.push([n,m,T,u])}a+=A,f+=A}}o.splice(0,i)}while(o.length>0)}function Ne(e,t,r,l,o="",i){const I=new Array(t.length+1);I[0]=[r,y+N,0];let s=0,a=!1;do{let[_,f,M]=I[s];if(M>=Z){--s;continue}I[s][1]+=A,++I[s][2];let E=e[_][f+p];if(E===w)continue;const u=e[_][E+D];_!==u&&(E=e[_][E+X],_=u),t[s]=M+C,I[++s]=[_,E+N,0];const T=e[_][E+d];T!==w&&(a&&l.write(o),a=!0,i(l,t,s,T))}while(s>=0)}function ye(e){const t=new te(e);return t.on("error",r=>{throw r}),t.on("messageerror",r=>{throw r}),t.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${t.threadId} exited with code ${r}`)}),t}function V(e,t){return new Promise(r=>{e.once("message",r),e.postMessage(t)})}async function Oe(e,t,r,l=""){r=K(r,Ee,fe);const o=await Ie(e,r,P,ce);r=o.length;const i=new SharedArrayBuffer(x*r+1<<4),I=new Int16Array(i),s=new Int16Array(i,2),a=new Uint32Array(i,4),_=new Float64Array(i,8),f=new Array(r),M=new Array(r);for(let n=0;n{f[c.id]=c.trie});for(let n=E.length-1;n>0;--n){const c=n-1>>1,R=n;E[c]=E[c].then(()=>E[R]).then(()=>V(M[c],{type:"merge_request",a:c,b:R,counts:a,maxes:s,mins:I,sums:_,tries:f})).then(h=>{f[h.id]=h.trie})}for(let n=0;nM[n].terminate());await Promise.all(E);const u=J(l,{fd:l.length<1?1:void 0,flags:"a",highWaterMark:ie}),T=Buffer.allocUnsafe(re);u.write("{"),Ne(f,T,0,u,", ",m),u.end(`} -`);function m(n,c,R,h){const O=Math.round(_[h<<1]/a[h<<2]);n.write(c.toString("utf8",0,R)),n.write("="),n.write((I[h<<3]/10).toFixed(1)),n.write("/"),n.write((O/10).toFixed(1)),n.write("/"),n.write((s[h<<3]/10).toFixed(1))}}async function Xe({end:e,filePath:t,id:r,start:l,counts:o,maxes:i,mins:I,sums:s}){if(l>=e)return{type:"process_response",id:r,trie:v(r,0)};let a=v(r),_=r*x+1;const f=Buffer.allocUnsafe(P),M=Q(t,{start:l,end:e-1,highWaterMark:le(e-l)});let E=0,u=0,T;for await(const c of M){const R=c.length;for(let h=0;h=R?i[c]:R,++o[c>>1],s[c>>2]+=R}return{type:"process_response",id:r,trie:a}}function He(e,t,r){return e[t]===ne?(++t,t+4>r?-(10*e[t]+e[t+2]-F):-(100*e[t]+10*e[t+1]+e[t+3]-k)):t+4>r?10*e[t]+e[t+2]-F:100*e[t]+10*e[t+1]+e[t+3]-k}function Le({a:e,b:t,tries:r,counts:l,maxes:o,mins:i,sums:I}){De(r,e,t,s);function s(a,_){a<<=3,_<<=3,i[a]=Math.min(i[a],i[_]),o[a]=Math.max(o[a],o[_]),l[a>>1]+=l[_>>1],I[a>>2]+=I[_>>2]}return{type:"merge_response",id:e,trie:r[e]}}if(j){const e=Y(import.meta.url);Oe(process.argv[2],e,z())}else L.addListener("message",async e=>{if(e.type==="process_request"){const t=await Xe(e);L.postMessage(t)}else if(e.type==="merge_request"){const t=Le(e);L.postMessage(t)}else throw new Error("Unknown message type")}); +import{availableParallelism as z}from"node:os";import{fileURLToPath as Y}from"node:url";import{isMainThread as j,parentPort as S}from"node:worker_threads";import{createWriteStream as J,createReadStream as Q}from"node:fs";import{open as ee}from"fs/promises";import{Worker as te}from"worker_threads";const x=1e4,re=100,P=107,ne=45,U=10,se=59,W=48,C=32,oe=192,B=16384,ae=1048576,ie=1048576,_e=152e-6,ce=B,F=11*W,b=111*W,Ee=1,fe=512;function k(e,t,r){return e>t?e<=r?e:r:t}async function Ie(e,t,r,R=0){const _=await ee(e);try{const o=(await _.stat()).size,f=Math.max(R,Math.floor(o/t)),E=Buffer.allocUnsafe(r),s=[];let a=0;for(let I=f;I=0&&ce.length&&(e=$(e,o+H)),e[g]+=H,e[_+p]=o,e[o+N]=e[G]),_=o}return[e,_]}function v(e=0,t=le){t=Math.max(q,t);const r=new Int32Array(new SharedArrayBuffer(t<<2));return r[g]=q,r[G]=e,r}function $(e,t=0){const r=e[g];t=Math.max(t,Math.ceil(r*ue));const R=new Int32Array(new SharedArrayBuffer(t<<2));for(let _=0;_e[s].length&&(e[s]=$(e[s],n+L),_.add(s)),e[s][g]+=L,e[s][a+p]=n,e[s][n+Te]=w,e[s][n+X]=l;else{const i=e[s][n+N];s!==i&&(n=e[s][n+X]),o.push([i,n,w,l])}}a+=D,u+=D}}o.splice(0,f)}while(o.length>0);return Array.from(_)}function Ne(e,t,r,R,_="",o){const f=new Array(t.length+1);f[0]=[r,O+y,0];let E=0,s=!1;do{let[a,I,u]=f[E];if(u>=K){--E;continue}f[E][1]+=D,++f[E][2];let c=e[a][I+p];if(c===h)continue;const m=e[a][c+N];a!==m&&(c=e[a][c+X],a=m),t[E]=u+C,f[++E]=[a,c+y,0];const l=e[a][c+d];l!==h&&(s&&R.write(_),s=!0,o(R,t,E,l))}while(E>=0)}function ye(e){const t=new te(e);return t.on("error",r=>{throw r}),t.on("messageerror",r=>{throw r}),t.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${t.threadId} exited with code ${r}`)}),t}function V(e,t){return new Promise(r=>{e.once("message",r),e.postMessage(t)})}async function Oe(e,t,r,R=""){r=k(r,Ee,fe);const _=await Ie(e,r,P,ce);r=_.length;const o=new SharedArrayBuffer(x*r+1<<4),f=new Int16Array(o),E=new Int16Array(o,2),s=new Uint32Array(o,4),a=new Float64Array(o,8),I=new Array(r),u=new Array(r);for(let n=0;n{I[i.id]=i.trie});for(let n=c.length-1;n>0;--n){const i=n-1>>1,M=n;c[i]=c[i].then(()=>c[M]).then(()=>V(u[i],{type:"merge_request",a:i,b:M,counts:s,maxes:E,mins:f,sums:a,tries:I})).then(T=>{for(const A of T.ids)I[A]=T.tries[A]})}for(let n=0;nu[n].terminate());await Promise.all(c);const m=J(R,{fd:R.length<1?1:void 0,flags:"a",highWaterMark:ie}),l=Buffer.allocUnsafe(re);m.write("{"),Ne(I,l,0,m,", ",w),m.end(`} +`);function w(n,i,M,T){const A=Math.round(a[T<<1]/s[T<<2]);n.write(i.toString("utf8",0,M)),n.write("="),n.write((f[T<<3]/10).toFixed(1)),n.write("/"),n.write((A/10).toFixed(1)),n.write("/"),n.write((E[T<<3]/10).toFixed(1))}}async function Xe({end:e,filePath:t,id:r,start:R,counts:_,maxes:o,mins:f,sums:E}){if(R>=e)return{type:"process_response",id:r,trie:v(r,0)};let s=v(r),a=r*x+1;const I=Buffer.allocUnsafe(P),u=Q(t,{start:R,end:e-1,highWaterMark:Re(e-R)});let c=0,m=0,l;for await(const i of u){const M=i.length;for(let T=0;T=M?o[i]:M,++_[i>>1],E[i>>2]+=M}return{type:"process_response",id:r,trie:s}}function He(e,t,r){return e[t]===ne?(++t,t+4>r?-(10*e[t]+e[t+2]-F):-(100*e[t]+10*e[t+1]+e[t+3]-b)):t+4>r?10*e[t]+e[t+2]-F:100*e[t]+10*e[t+1]+e[t+3]-b}function Se({a:e,b:t,tries:r,counts:R,maxes:_,mins:o,sums:f}){function E(s,a){s<<=3,a<<=3,o[s]=Math.min(o[s],o[a]),_[s]=Math.max(_[s],_[a]),R[s>>1]+=R[a>>1],f[s>>2]+=f[a>>2]}return{type:"merge_response",ids:De(r,e,t,E),tries:r}}if(j){const e=Y(import.meta.url);Oe(process.argv[2],e,z())}else S.addListener("message",async e=>{if(e.type==="process_request"){const t=await Xe(e);S.postMessage(t)}else if(e.type==="merge_request"){const t=Se(e);S.postMessage(t)}else throw new Error("Unknown message type")}); //# sourceMappingURL=index.mjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index 10fc1db..c65e417 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1 +1 @@ -{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN } from \"./utf8\";\n\n// Configurable constants\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 524288; // 2 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Internal trie pointer\n\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Cross-trie pointer (aka redirect)\n\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a null / undefined trie element.\n */\nexport const TRIE_NULL = 0;\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_PTR_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_XPTR_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate new node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach and initialize node\n trie[index + TRIE_PTR_IDX_IDX] = child;\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): void {\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_PTR_IDX_IDX];\n if (ri === TRIE_NULL) {\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n continue;\n }\n\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_PTR_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate new redirect in left trie\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Add new redirect\n tries[at][li + TRIE_XPTR_ID_IDX] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n ai = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_B0_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n mergeLeft(tries, a, b, mergeStations);\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n return { type: \"merge_response\", id: a, trie: tries[a] };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n const res = await runWorker(msg as ProcessRequest);\n parentPort!.postMessage(res);\n } else if (msg.type === \"merge_request\") {\n const res = merge(msg as MergeRequest);\n parentPort!.postMessage(res);\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_B0_MIN","UTF8_B0_2B_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","CHAR_ZERO_11","CHAR_ZERO_111","MIN_WORKERS","MAX_WORKERS","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_IDX","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_IDX","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","stations","createReadStream","bufI","tempI","leaf","chunk","N","tempV","parseDouble","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN } from \"./utf8\";\n\n// Configurable constants\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 524288; // 2 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Internal trie pointer\n\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Cross-trie pointer (aka redirect)\n\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a null / undefined trie element.\n */\nexport const TRIE_NULL = 0;\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_PTR_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_XPTR_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index + TRIE_PTR_IDX_IDX] = child;\n // Initialize node\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node + TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN);\n let child = tries[trie][ptr + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TRIE_NODE_ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_PTR_IDX_IDX];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_PTR_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai + TRIE_PTR_IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TRIE_XPTR_ID_IDX] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_B0_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { type: \"merge_response\", ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n const res = await runWorker(msg as ProcessRequest);\n parentPort!.postMessage(res);\n } else if (msg.type === \"merge_request\") {\n const res = merge(msg as MergeRequest);\n parentPort!.postMessage(res);\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_B0_MIN","UTF8_B0_2B_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","CHAR_ZERO_11","CHAR_ZERO_111","MIN_WORKERS","MAX_WORKERS","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_IDX","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_IDX","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","stations","createReadStream","bufI","tempI","leaf","chunk","N","tempV","parseDouble","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/src/main.ts b/src/main/nodejs/havelessbemore/src/main.ts index a54ab7d..27d7f8b 100644 --- a/src/main/nodejs/havelessbemore/src/main.ts +++ b/src/main/nodejs/havelessbemore/src/main.ts @@ -1,6 +1,8 @@ import { WriteStream, createWriteStream } from "node:fs"; import { Worker } from "node:worker_threads"; +import type { MergeRequest } from "./types/mergeRequest"; +import type { MergeResponse } from "./types/mergeResponse"; import type { ProcessRequest } from "./types/processRequest"; import type { ProcessResponse } from "./types/processResponse"; @@ -13,8 +15,6 @@ import { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from "./constants/stream"; import { MAX_WORKERS, MIN_WORKERS } from "./constants/workers"; import { clamp, getFileChunks } from "./utils/stream"; import { print } from "./utils/utf8Trie"; -import { MergeResponse } from "./types/mergeResponse"; -import { MergeRequest } from "./types/mergeRequest"; import { createWorker, exec } from "./utils/worker"; export async function run( @@ -88,7 +88,9 @@ export async function run( }), ) .then((res) => { - tries[res.id] = res.trie; + for (const id of res.ids) { + tries[id] = res.tries[id]; + } }); } diff --git a/src/main/nodejs/havelessbemore/src/types/mergeResponse.ts b/src/main/nodejs/havelessbemore/src/types/mergeResponse.ts index 756a958..b980857 100644 --- a/src/main/nodejs/havelessbemore/src/types/mergeResponse.ts +++ b/src/main/nodejs/havelessbemore/src/types/mergeResponse.ts @@ -2,6 +2,6 @@ import { Message } from "./message"; export interface MergeResponse extends Message { type: "merge_response"; - id: number; - trie: Int32Array; + ids: number[]; + tries: Int32Array[]; } diff --git a/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts b/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts index 280b965..8c27115 100644 --- a/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts +++ b/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts @@ -33,14 +33,15 @@ export function add( index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN); let child = trie[index + TRIE_PTR_IDX_IDX]; if (child === TRIE_NULL) { - // Allocate new node + // Allocate node child = trie[TRIE_SIZE_IDX]; if (child + TRIE_NODE_MEM > trie.length) { trie = grow(trie, child + TRIE_NODE_MEM); } trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM; - // Attach and initialize node + // Attach node trie[index + TRIE_PTR_IDX_IDX] = child; + // Initialize node trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX]; } index = child; @@ -49,6 +50,32 @@ export function add( return [trie, index]; } +export function get( + tries: Int32Array[], + trie: number, + key: ArrayLike, + min: number, + max: number, +): number | undefined { + let node = TRIE_ROOT_IDX; + while (min < max) { + const ptr = + node + TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN); + let child = tries[trie][ptr + TRIE_PTR_IDX_IDX]; + if (child === TRIE_NULL) { + return undefined; + } + // Resolve redirect, if any + const childTrie = tries[trie][child + TRIE_NODE_ID_IDX]; + if (childTrie !== trie) { + child = tries[trie][child + TRIE_XPTR_IDX_IDX]; + trie = childTrie; + } + node = child; + } + return node; +} + export function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array { size = Math.max(TRIE_MEM, size); const trie = new Int32Array(new SharedArrayBuffer(size << 2)); @@ -72,7 +99,8 @@ export function mergeLeft( at: number, bt: number, mergeFn: (ai: number, bi: number) => void, -): void { +): number[] { + const grown = new Set(); const queue: [number, number, number, number][] = [ [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX], ]; @@ -104,39 +132,37 @@ export function mergeLeft( while (bi < bn) { // If right child is null let ri = tries[bt][bi + TRIE_PTR_IDX_IDX]; - if (ri === TRIE_NULL) { - // Move to next children - ai += TRIE_PTR_MEM; - bi += TRIE_PTR_MEM; - continue; - } - - // Resolve right child if redirect - const rt = tries[bt][ri + TRIE_NODE_ID_IDX]; - if (bt !== rt) { - ri = tries[bt][ri + TRIE_XPTR_IDX_IDX]; - } - - // If left child is null - let li = tries[at][ai + TRIE_PTR_IDX_IDX]; - if (li === TRIE_NULL) { - // Allocate new redirect in left trie - li = tries[at][TRIE_SIZE_IDX]; - if (li + TRIE_XPTR_MEM > tries[at].length) { - tries[at] = grow(tries[at], li + TRIE_XPTR_MEM); + if (ri !== TRIE_NULL) { + // Resolve right child if redirect + const rt = tries[bt][ri + TRIE_NODE_ID_IDX]; + if (bt !== rt) { + ri = tries[bt][ri + TRIE_XPTR_IDX_IDX]; } - tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM; - // Add new redirect - tries[at][li + TRIE_XPTR_ID_IDX] = rt; - tries[at][li + TRIE_XPTR_IDX_IDX] = ri; - } else { - // Resolve left child if redirect - const lt = tries[at][li + TRIE_NODE_ID_IDX]; - if (at !== lt) { - ai = tries[at][li + TRIE_XPTR_IDX_IDX]; + + // If left child is null + let li = tries[at][ai + TRIE_PTR_IDX_IDX]; + if (li === TRIE_NULL) { + // Allocate redirect + li = tries[at][TRIE_SIZE_IDX]; + if (li + TRIE_XPTR_MEM > tries[at].length) { + tries[at] = grow(tries[at], li + TRIE_XPTR_MEM); + grown.add(at); + } + tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM; + // Attach redirect + tries[at][ai + TRIE_PTR_IDX_IDX] = li; + // Initialize redirect + tries[at][li + TRIE_XPTR_ID_IDX] = rt; + tries[at][li + TRIE_XPTR_IDX_IDX] = ri; + } else { + // Resolve left child if redirect + const lt = tries[at][li + TRIE_NODE_ID_IDX]; + if (at !== lt) { + li = tries[at][li + TRIE_XPTR_IDX_IDX]; + } + // Merge children + queue.push([lt, li, rt, ri]); } - // Merge children - queue.push([lt, li, rt, ri]); } // Move to next children @@ -146,6 +172,7 @@ export function mergeLeft( } queue.splice(0, Q); } while (queue.length > 0); + return Array.from(grown); } export function print( diff --git a/src/main/nodejs/havelessbemore/src/worker.ts b/src/main/nodejs/havelessbemore/src/worker.ts index 127ba32..ada7600 100644 --- a/src/main/nodejs/havelessbemore/src/worker.ts +++ b/src/main/nodejs/havelessbemore/src/worker.ts @@ -114,7 +114,6 @@ export function merge({ mins, sums, }: MergeRequest): MergeResponse { - mergeLeft(tries, a, b, mergeStations); function mergeStations(ai: number, bi: number): void { ai <<= 3; bi <<= 3; @@ -123,5 +122,6 @@ export function merge({ counts[ai >> 1] += counts[bi >> 1]; sums[ai >> 2] += sums[bi >> 2]; } - return { type: "merge_response", id: a, trie: tries[a] }; + const ids = mergeLeft(tries, a, b, mergeStations); + return { type: "merge_response", ids, tries }; } From 5d8d0845322c196d9d07f9bf64399c1732699697 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Thu, 23 May 2024 15:54:36 -0400 Subject: [PATCH 24/69] Update comments, Rename utf8 constants, Remove unused constants --- src/main/nodejs/havelessbemore/dist/index.cjs | 4 +- .../nodejs/havelessbemore/dist/index.cjs.map | 2 +- src/main/nodejs/havelessbemore/dist/index.mjs | 4 +- .../nodejs/havelessbemore/dist/index.mjs.map | 2 +- .../src/constants/constraints.ts | 52 +++++++++++++++++-- .../havelessbemore/src/constants/utf8.ts | 27 +++++----- .../havelessbemore/src/constants/utf8Trie.ts | 34 +++++++++--- .../havelessbemore/src/constants/workers.ts | 19 +++++++ .../havelessbemore/src/utils/utf8Trie.ts | 8 +-- 9 files changed, 117 insertions(+), 35 deletions(-) diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs b/src/main/nodejs/havelessbemore/dist/index.cjs index e9c4c03..16650ff 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs +++ b/src/main/nodejs/havelessbemore/dist/index.cjs @@ -24,6 +24,6 @@ * SOFTWARE. */ -"use strict";var Y=require("node:os"),J=require("node:url"),X=require("node:worker_threads"),U=require("node:fs"),Q=require("fs/promises"),ee=require("worker_threads"),P=typeof document<"u"?document.currentScript:null;const x=1e4,te=100,W=107,re=45,C=10,ne=59,q=48,k=32,se=192,v=16384,ae=1048576,oe=1048576,ie=152e-6,_e=v,F=11*q,b=111*q,ce=1,ue=512;function B(e,t,r){return e>t?e<=r?e:r:t}async function fe(e,t,r,I=0){const _=await Q.open(e);try{const a=(await _.stat()).size,f=Math.max(I,Math.floor(a/t)),u=Buffer.allocUnsafe(r),s=[];let o=0;for(let E=f;E=0&&ce.length&&(e=j(e,a+H)),e[y]+=H,e[_+p]=a,e[a+D]=e[G]),_=a}return[e,_]}function V(e=0,t=Ie){t=Math.max($,t);const r=new Int32Array(new SharedArrayBuffer(t<<2));return r[y]=$,r[G]=e,r}function j(e,t=0){const r=e[y];t=Math.max(t,Math.ceil(r*Re));const I=new Int32Array(new SharedArrayBuffer(t<<2));for(let _=0;_e[s].length&&(e[s]=j(e[s],n+L),_.add(s)),e[s][y]+=L,e[s][o+p]=n,e[s][n+Me]=w,e[s][n+S]=R;else{const i=e[s][n+D];s!==i&&(n=e[s][n+S]),a.push([i,n,w,R])}}o+=g,l+=g}}a.splice(0,f)}while(a.length>0);return Array.from(_)}function ge(e,t,r,I,_="",a){const f=new Array(t.length+1);f[0]=[r,O+N,0];let u=0,s=!1;do{let[o,E,l]=f[u];if(l>=K){--u;continue}f[u][1]+=g,++f[u][2];let c=e[o][E+p];if(c===h)continue;const d=e[o][c+D];o!==d&&(c=e[o][c+S],o=d),t[u]=l+k,f[++u]=[o,c+N,0];const R=e[o][c+A];R!==h&&(s&&I.write(_),s=!0,a(I,t,u,R))}while(u>=0)}function De(e){const t=new ee.Worker(e);return t.on("error",r=>{throw r}),t.on("messageerror",r=>{throw r}),t.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${t.threadId} exited with code ${r}`)}),t}function z(e,t){return new Promise(r=>{e.once("message",r),e.postMessage(t)})}async function Ne(e,t,r,I=""){r=B(r,ce,ue);const _=await fe(e,r,W,_e);r=_.length;const a=new SharedArrayBuffer(x*r+1<<4),f=new Int16Array(a),u=new Int16Array(a,2),s=new Uint32Array(a,4),o=new Float64Array(a,8),E=new Array(r),l=new Array(r);for(let n=0;n{E[i.id]=i.trie});for(let n=c.length-1;n>0;--n){const i=n-1>>1,M=n;c[i]=c[i].then(()=>c[M]).then(()=>z(l[i],{type:"merge_request",a:i,b:M,counts:s,maxes:u,mins:f,sums:o,tries:E})).then(T=>{for(const m of T.ids)E[m]=T.tries[m]})}for(let n=0;nl[n].terminate());await Promise.all(c);const d=U.createWriteStream(I,{fd:I.length<1?1:void 0,flags:"a",highWaterMark:oe}),R=Buffer.allocUnsafe(te);d.write("{"),ge(E,R,0,d,", ",w),d.end(`} -`);function w(n,i,M,T){const m=Math.round(o[T<<1]/s[T<<2]);n.write(i.toString("utf8",0,M)),n.write("="),n.write((f[T<<3]/10).toFixed(1)),n.write("/"),n.write((m/10).toFixed(1)),n.write("/"),n.write((u[T<<3]/10).toFixed(1))}}async function Oe({end:e,filePath:t,id:r,start:I,counts:_,maxes:a,mins:f,sums:u}){if(I>=e)return{type:"process_response",id:r,trie:V(r,0)};let s=V(r),o=r*x+1;const E=Buffer.allocUnsafe(W),l=U.createReadStream(t,{start:I,end:e-1,highWaterMark:Ee(e-I)});let c=0,d=0,R;for await(const i of l){const M=i.length;for(let T=0;T=M?a[i]:M,++_[i>>1],u[i>>2]+=M}return{type:"process_response",id:r,trie:s}}function Xe(e,t,r){return e[t]===re?(++t,t+4>r?-(10*e[t]+e[t+2]-F):-(100*e[t]+10*e[t+1]+e[t+3]-b)):t+4>r?10*e[t]+e[t+2]-F:100*e[t]+10*e[t+1]+e[t+3]-b}function Se({a:e,b:t,tries:r,counts:I,maxes:_,mins:a,sums:f}){function u(s,o){s<<=3,o<<=3,a[s]=Math.min(a[s],a[o]),_[s]=Math.max(_[s],_[o]),I[s>>1]+=I[o>>1],f[s>>2]+=f[o>>2]}return{type:"merge_response",ids:ye(r,e,t,u),tries:r}}if(X.isMainThread){const e=J.fileURLToPath(typeof document>"u"?require("url").pathToFileURL(__filename).href:P&&P.src||new URL("index.cjs",document.baseURI).href);Ne(process.argv[2],e,Y.availableParallelism())}else X.parentPort.addListener("message",async e=>{if(e.type==="process_request"){const t=await Oe(e);X.parentPort.postMessage(t)}else if(e.type==="merge_request"){const t=Se(e);X.parentPort.postMessage(t)}else throw new Error("Unknown message type")}); +"use strict";var z=require("node:os"),J=require("node:url"),X=require("node:worker_threads"),P=require("node:fs"),Q=require("fs/promises"),ee=require("worker_threads"),U=typeof document<"u"?document.currentScript:null;const x=1e4,te=100,W=107,re=45,C=10,ne=59,q=48,k=32,se=216,v=16384,ae=1048576,oe=1048576,ie=152e-6,_e=v,F=11*q,b=111*q,ce=1,ue=512;function B(e,t,r){return e>t?e<=r?e:r:t}async function fe(e,t,r,I=0){const _=await Q.open(e);try{const a=(await _.stat()).size,f=Math.max(I,Math.floor(a/t)),u=Buffer.allocUnsafe(r),s=[];let o=0;for(let E=f;E=0&&ce.length&&(e=V(e,a+H)),e[y]+=H,e[_+p]=a,e[a+D]=e[G]),_=a}return[e,_]}function $(e=0,t=Ie){t=Math.max(Y,t);const r=new Int32Array(new SharedArrayBuffer(t<<2));return r[y]=Y,r[G]=e,r}function V(e,t=0){const r=e[y];t=Math.max(t,Math.ceil(r*Re));const I=new Int32Array(new SharedArrayBuffer(t<<2));for(let _=0;_e[s].length&&(e[s]=V(e[s],n+L),_.add(s)),e[s][y]+=L,e[s][o+p]=n,e[s][n+Me]=w,e[s][n+S]=R;else{const i=e[s][n+D];s!==i&&(n=e[s][n+S]),a.push([i,n,w,R])}}o+=g,l+=g}}a.splice(0,f)}while(a.length>0);return Array.from(_)}function ge(e,t,r,I,_="",a){const f=new Array(t.length+1);f[0]=[r,O+N,0];let u=0,s=!1;do{let[o,E,l]=f[u];if(l>=K){--u;continue}f[u][1]+=g,++f[u][2];let c=e[o][E+p];if(c===h)continue;const d=e[o][c+D];o!==d&&(c=e[o][c+S],o=d),t[u]=l+k,f[++u]=[o,c+N,0];const R=e[o][c+A];R!==h&&(s&&I.write(_),s=!0,a(I,t,u,R))}while(u>=0)}function De(e){const t=new ee.Worker(e);return t.on("error",r=>{throw r}),t.on("messageerror",r=>{throw r}),t.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${t.threadId} exited with code ${r}`)}),t}function j(e,t){return new Promise(r=>{e.once("message",r),e.postMessage(t)})}async function Ne(e,t,r,I=""){r=B(r,ce,ue);const _=await fe(e,r,W,_e);r=_.length;const a=new SharedArrayBuffer(x*r+1<<4),f=new Int16Array(a),u=new Int16Array(a,2),s=new Uint32Array(a,4),o=new Float64Array(a,8),E=new Array(r),l=new Array(r);for(let n=0;n{E[i.id]=i.trie});for(let n=c.length-1;n>0;--n){const i=n-1>>1,M=n;c[i]=c[i].then(()=>c[M]).then(()=>j(l[i],{type:"merge_request",a:i,b:M,counts:s,maxes:u,mins:f,sums:o,tries:E})).then(T=>{for(const m of T.ids)E[m]=T.tries[m]})}for(let n=0;nl[n].terminate());await Promise.all(c);const d=P.createWriteStream(I,{fd:I.length<1?1:void 0,flags:"a",highWaterMark:oe}),R=Buffer.allocUnsafe(te);d.write("{"),ge(E,R,0,d,", ",w),d.end(`} +`);function w(n,i,M,T){const m=Math.round(o[T<<1]/s[T<<2]);n.write(i.toString("utf8",0,M)),n.write("="),n.write((f[T<<3]/10).toFixed(1)),n.write("/"),n.write((m/10).toFixed(1)),n.write("/"),n.write((u[T<<3]/10).toFixed(1))}}async function Oe({end:e,filePath:t,id:r,start:I,counts:_,maxes:a,mins:f,sums:u}){if(I>=e)return{type:"process_response",id:r,trie:$(r,0)};let s=$(r),o=r*x+1;const E=Buffer.allocUnsafe(W),l=P.createReadStream(t,{start:I,end:e-1,highWaterMark:Ee(e-I)});let c=0,d=0,R;for await(const i of l){const M=i.length;for(let T=0;T=M?a[i]:M,++_[i>>1],u[i>>2]+=M}return{type:"process_response",id:r,trie:s}}function Xe(e,t,r){return e[t]===re?(++t,t+4>r?-(10*e[t]+e[t+2]-F):-(100*e[t]+10*e[t+1]+e[t+3]-b)):t+4>r?10*e[t]+e[t+2]-F:100*e[t]+10*e[t+1]+e[t+3]-b}function Se({a:e,b:t,tries:r,counts:I,maxes:_,mins:a,sums:f}){function u(s,o){s<<=3,o<<=3,a[s]=Math.min(a[s],a[o]),_[s]=Math.max(_[s],_[o]),I[s>>1]+=I[o>>1],f[s>>2]+=f[o>>2]}return{type:"merge_response",ids:ye(r,e,t,u),tries:r}}if(X.isMainThread){const e=J.fileURLToPath(typeof document>"u"?require("url").pathToFileURL(__filename).href:U&&U.src||new URL("index.cjs",document.baseURI).href);Ne(process.argv[2],e,z.availableParallelism())}else X.parentPort.addListener("message",async e=>{if(e.type==="process_request"){const t=await Oe(e);X.parentPort.postMessage(t)}else if(e.type==="merge_request"){const t=Se(e);X.parentPort.postMessage(t)}else throw new Error("Unknown message type")}); //# sourceMappingURL=index.cjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs.map b/src/main/nodejs/havelessbemore/dist/index.cjs.map index e26d934..66ac565 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.cjs.map @@ -1 +1 @@ -{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN } from \"./utf8\";\n\n// Configurable constants\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 524288; // 2 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Internal trie pointer\n\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Cross-trie pointer (aka redirect)\n\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a null / undefined trie element.\n */\nexport const TRIE_NULL = 0;\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_PTR_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_XPTR_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index + TRIE_PTR_IDX_IDX] = child;\n // Initialize node\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node + TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN);\n let child = tries[trie][ptr + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TRIE_NODE_ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_PTR_IDX_IDX];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_PTR_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai + TRIE_PTR_IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TRIE_XPTR_ID_IDX] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_B0_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { type: \"merge_response\", ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n const res = await runWorker(msg as ProcessRequest);\n parentPort!.postMessage(res);\n } else if (msg.type === \"merge_request\") {\n const res = merge(msg as MergeRequest);\n parentPort!.postMessage(res);\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_B0_MIN","UTF8_B0_2B_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","CHAR_ZERO_11","CHAR_ZERO_111","MIN_WORKERS","MAX_WORKERS","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_IDX","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_IDX","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","stations","createReadStream","bufI","tempI","leaf","chunk","N","tempV","parseDouble","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","_documentCurrentScript","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n * \n * @remarks\n * \n * Changing this value affects the `count` and \n * `sum` values used for calculating a station's\n * average temperature. \n * \n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n * \n * @remarks\n * \n * Changing this value affects the indexing of trie nodes.\n * \n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n * \n * @remarks\n * \n * Changing this value affects the indexing of trie nodes.\n * \n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n * \n * @remarks\n * \n * Changing this value affects the `min`, `max` and `sum` values \n * used for calculating a station's min, max and avg \n * temperatures, respectively. \n * \n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n * \n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n * \n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n * \n * @remarks\n * \n * This limit should be sufficient for most use cases. \n * However, feel free to adjust up or down as needed. \n * \n * There is not much basis for the current value.\n * Development was done with at most 8 workers and \n * a reasonable input file, with memory never exceeding \n * 20 MiB total across all workers.\n * \n * In theory, the challenge constraints allow for input \n * files that would require each worker using upwards of \n * 800 MiB; 10K stations with completely unique 100 byte names, \n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n// \n// Controls trie behavior such as the default \n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_PTR_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_XPTR_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_BYTE_MIN);\n let child = trie[index + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index + TRIE_PTR_IDX_IDX] = child;\n // Initialize node\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node + TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TRIE_NODE_ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_PTR_IDX_IDX];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_PTR_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai + TRIE_PTR_IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TRIE_XPTR_ID_IDX] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { type: \"merge_response\", ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n const res = await runWorker(msg as ProcessRequest);\n parentPort!.postMessage(res);\n } else if (msg.type === \"merge_request\") {\n const res = merge(msg as MergeRequest);\n parentPort!.postMessage(res);\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","CHAR_ZERO_11","CHAR_ZERO_111","MIN_WORKERS","MAX_WORKERS","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_IDX","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_IDX","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","stations","createReadStream","bufI","tempI","leaf","chunk","N","tempV","parseDouble","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","_documentCurrentScript","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index 57b7074..b86b1ce 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -24,6 +24,6 @@ * SOFTWARE. */ -import{availableParallelism as z}from"node:os";import{fileURLToPath as Y}from"node:url";import{isMainThread as j,parentPort as S}from"node:worker_threads";import{createWriteStream as J,createReadStream as Q}from"node:fs";import{open as ee}from"fs/promises";import{Worker as te}from"worker_threads";const x=1e4,re=100,P=107,ne=45,U=10,se=59,W=48,C=32,oe=192,B=16384,ae=1048576,ie=1048576,_e=152e-6,ce=B,F=11*W,b=111*W,Ee=1,fe=512;function k(e,t,r){return e>t?e<=r?e:r:t}async function Ie(e,t,r,R=0){const _=await ee(e);try{const o=(await _.stat()).size,f=Math.max(R,Math.floor(o/t)),E=Buffer.allocUnsafe(r),s=[];let a=0;for(let I=f;I=0&&ce.length&&(e=$(e,o+H)),e[g]+=H,e[_+p]=o,e[o+N]=e[G]),_=o}return[e,_]}function v(e=0,t=le){t=Math.max(q,t);const r=new Int32Array(new SharedArrayBuffer(t<<2));return r[g]=q,r[G]=e,r}function $(e,t=0){const r=e[g];t=Math.max(t,Math.ceil(r*ue));const R=new Int32Array(new SharedArrayBuffer(t<<2));for(let _=0;_e[s].length&&(e[s]=$(e[s],n+L),_.add(s)),e[s][g]+=L,e[s][a+p]=n,e[s][n+Te]=w,e[s][n+X]=l;else{const i=e[s][n+N];s!==i&&(n=e[s][n+X]),o.push([i,n,w,l])}}a+=D,u+=D}}o.splice(0,f)}while(o.length>0);return Array.from(_)}function Ne(e,t,r,R,_="",o){const f=new Array(t.length+1);f[0]=[r,O+y,0];let E=0,s=!1;do{let[a,I,u]=f[E];if(u>=K){--E;continue}f[E][1]+=D,++f[E][2];let c=e[a][I+p];if(c===h)continue;const m=e[a][c+N];a!==m&&(c=e[a][c+X],a=m),t[E]=u+C,f[++E]=[a,c+y,0];const l=e[a][c+d];l!==h&&(s&&R.write(_),s=!0,o(R,t,E,l))}while(E>=0)}function ye(e){const t=new te(e);return t.on("error",r=>{throw r}),t.on("messageerror",r=>{throw r}),t.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${t.threadId} exited with code ${r}`)}),t}function V(e,t){return new Promise(r=>{e.once("message",r),e.postMessage(t)})}async function Oe(e,t,r,R=""){r=k(r,Ee,fe);const _=await Ie(e,r,P,ce);r=_.length;const o=new SharedArrayBuffer(x*r+1<<4),f=new Int16Array(o),E=new Int16Array(o,2),s=new Uint32Array(o,4),a=new Float64Array(o,8),I=new Array(r),u=new Array(r);for(let n=0;n{I[i.id]=i.trie});for(let n=c.length-1;n>0;--n){const i=n-1>>1,M=n;c[i]=c[i].then(()=>c[M]).then(()=>V(u[i],{type:"merge_request",a:i,b:M,counts:s,maxes:E,mins:f,sums:a,tries:I})).then(T=>{for(const A of T.ids)I[A]=T.tries[A]})}for(let n=0;nu[n].terminate());await Promise.all(c);const m=J(R,{fd:R.length<1?1:void 0,flags:"a",highWaterMark:ie}),l=Buffer.allocUnsafe(re);m.write("{"),Ne(I,l,0,m,", ",w),m.end(`} -`);function w(n,i,M,T){const A=Math.round(a[T<<1]/s[T<<2]);n.write(i.toString("utf8",0,M)),n.write("="),n.write((f[T<<3]/10).toFixed(1)),n.write("/"),n.write((A/10).toFixed(1)),n.write("/"),n.write((E[T<<3]/10).toFixed(1))}}async function Xe({end:e,filePath:t,id:r,start:R,counts:_,maxes:o,mins:f,sums:E}){if(R>=e)return{type:"process_response",id:r,trie:v(r,0)};let s=v(r),a=r*x+1;const I=Buffer.allocUnsafe(P),u=Q(t,{start:R,end:e-1,highWaterMark:Re(e-R)});let c=0,m=0,l;for await(const i of u){const M=i.length;for(let T=0;T=M?o[i]:M,++_[i>>1],E[i>>2]+=M}return{type:"process_response",id:r,trie:s}}function He(e,t,r){return e[t]===ne?(++t,t+4>r?-(10*e[t]+e[t+2]-F):-(100*e[t]+10*e[t+1]+e[t+3]-b)):t+4>r?10*e[t]+e[t+2]-F:100*e[t]+10*e[t+1]+e[t+3]-b}function Se({a:e,b:t,tries:r,counts:R,maxes:_,mins:o,sums:f}){function E(s,a){s<<=3,a<<=3,o[s]=Math.min(o[s],o[a]),_[s]=Math.max(_[s],_[a]),R[s>>1]+=R[a>>1],f[s>>2]+=f[a>>2]}return{type:"merge_response",ids:De(r,e,t,E),tries:r}}if(j){const e=Y(import.meta.url);Oe(process.argv[2],e,z())}else S.addListener("message",async e=>{if(e.type==="process_request"){const t=await Xe(e);S.postMessage(t)}else if(e.type==="merge_request"){const t=Se(e);S.postMessage(t)}else throw new Error("Unknown message type")}); +import{availableParallelism as V}from"node:os";import{fileURLToPath as z}from"node:url";import{isMainThread as j,parentPort as S}from"node:worker_threads";import{createWriteStream as J,createReadStream as Q}from"node:fs";import{open as ee}from"fs/promises";import{Worker as te}from"worker_threads";const P=1e4,re=100,x=107,ne=45,U=10,se=59,W=48,C=32,oe=216,F=16384,ae=1048576,ie=1048576,_e=152e-6,ce=F,b=11*W,k=111*W,Ee=1,fe=512;function B(e,t,r){return e>t?e<=r?e:r:t}async function Ie(e,t,r,R=0){const _=await ee(e);try{const o=(await _.stat()).size,f=Math.max(R,Math.floor(o/t)),E=Buffer.allocUnsafe(r),s=[];let a=0;for(let I=f;I=0&&ce.length&&(e=Y(e,o+H)),e[g]+=H,e[_+p]=o,e[o+N]=e[G]),_=o}return[e,_]}function v(e=0,t=le){t=Math.max(q,t);const r=new Int32Array(new SharedArrayBuffer(t<<2));return r[g]=q,r[G]=e,r}function Y(e,t=0){const r=e[g];t=Math.max(t,Math.ceil(r*ue));const R=new Int32Array(new SharedArrayBuffer(t<<2));for(let _=0;_e[s].length&&(e[s]=Y(e[s],n+L),_.add(s)),e[s][g]+=L,e[s][a+p]=n,e[s][n+Te]=w,e[s][n+X]=l;else{const i=e[s][n+N];s!==i&&(n=e[s][n+X]),o.push([i,n,w,l])}}a+=D,u+=D}}o.splice(0,f)}while(o.length>0);return Array.from(_)}function Ne(e,t,r,R,_="",o){const f=new Array(t.length+1);f[0]=[r,O+y,0];let E=0,s=!1;do{let[a,I,u]=f[E];if(u>=K){--E;continue}f[E][1]+=D,++f[E][2];let c=e[a][I+p];if(c===h)continue;const m=e[a][c+N];a!==m&&(c=e[a][c+X],a=m),t[E]=u+C,f[++E]=[a,c+y,0];const l=e[a][c+d];l!==h&&(s&&R.write(_),s=!0,o(R,t,E,l))}while(E>=0)}function ye(e){const t=new te(e);return t.on("error",r=>{throw r}),t.on("messageerror",r=>{throw r}),t.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${t.threadId} exited with code ${r}`)}),t}function $(e,t){return new Promise(r=>{e.once("message",r),e.postMessage(t)})}async function Oe(e,t,r,R=""){r=B(r,Ee,fe);const _=await Ie(e,r,x,ce);r=_.length;const o=new SharedArrayBuffer(P*r+1<<4),f=new Int16Array(o),E=new Int16Array(o,2),s=new Uint32Array(o,4),a=new Float64Array(o,8),I=new Array(r),u=new Array(r);for(let n=0;n{I[i.id]=i.trie});for(let n=c.length-1;n>0;--n){const i=n-1>>1,M=n;c[i]=c[i].then(()=>c[M]).then(()=>$(u[i],{type:"merge_request",a:i,b:M,counts:s,maxes:E,mins:f,sums:a,tries:I})).then(T=>{for(const A of T.ids)I[A]=T.tries[A]})}for(let n=0;nu[n].terminate());await Promise.all(c);const m=J(R,{fd:R.length<1?1:void 0,flags:"a",highWaterMark:ie}),l=Buffer.allocUnsafe(re);m.write("{"),Ne(I,l,0,m,", ",w),m.end(`} +`);function w(n,i,M,T){const A=Math.round(a[T<<1]/s[T<<2]);n.write(i.toString("utf8",0,M)),n.write("="),n.write((f[T<<3]/10).toFixed(1)),n.write("/"),n.write((A/10).toFixed(1)),n.write("/"),n.write((E[T<<3]/10).toFixed(1))}}async function Xe({end:e,filePath:t,id:r,start:R,counts:_,maxes:o,mins:f,sums:E}){if(R>=e)return{type:"process_response",id:r,trie:v(r,0)};let s=v(r),a=r*P+1;const I=Buffer.allocUnsafe(x),u=Q(t,{start:R,end:e-1,highWaterMark:Re(e-R)});let c=0,m=0,l;for await(const i of u){const M=i.length;for(let T=0;T=M?o[i]:M,++_[i>>1],E[i>>2]+=M}return{type:"process_response",id:r,trie:s}}function He(e,t,r){return e[t]===ne?(++t,t+4>r?-(10*e[t]+e[t+2]-b):-(100*e[t]+10*e[t+1]+e[t+3]-k)):t+4>r?10*e[t]+e[t+2]-b:100*e[t]+10*e[t+1]+e[t+3]-k}function Se({a:e,b:t,tries:r,counts:R,maxes:_,mins:o,sums:f}){function E(s,a){s<<=3,a<<=3,o[s]=Math.min(o[s],o[a]),_[s]=Math.max(_[s],_[a]),R[s>>1]+=R[a>>1],f[s>>2]+=f[a>>2]}return{type:"merge_response",ids:De(r,e,t,E),tries:r}}if(j){const e=z(import.meta.url);Oe(process.argv[2],e,V())}else S.addListener("message",async e=>{if(e.type==="process_request"){const t=await Xe(e);S.postMessage(t)}else if(e.type==="merge_request"){const t=Se(e);S.postMessage(t)}else throw new Error("Unknown message type")}); //# sourceMappingURL=index.mjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index c65e417..2e4f5f4 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1 +1 @@ -{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries in the file (i.e. 1 billion).\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations (i.e. 10 thousand).\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum length in bytes of a station name (i.e. 100 bytes).\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = 107;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of the first byte of a UTF-8 code point.\n *\n * Ignores the control code points from U+0000 to U+001F.\n *\n * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset}\n */\nexport const UTF8_B0_MIN = 32;\n\n/**\n * The minimum value for noninitial bytes of a UTF-8 code point.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BN_MIN = 128;\n\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\nexport const UTF8_B0_MAX = UTF8_B0_4B_MAX;\n\nexport const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1;\nexport const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1;\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_B0_2B_LEN } from \"./utf8\";\n\n// Configurable constants\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 524288; // 2 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Internal trie pointer\n\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Cross-trie pointer (aka redirect)\n\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a null / undefined trie element.\n */\nexport const TRIE_NULL = 0;\n\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_PTR_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_XPTR_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_B0_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN);\n let child = trie[index + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index + TRIE_PTR_IDX_IDX] = child;\n // Initialize node\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node + TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN);\n let child = tries[trie][ptr + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TRIE_NODE_ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_PTR_IDX_IDX];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_PTR_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai + TRIE_PTR_IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TRIE_XPTR_ID_IDX] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_B0_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { type: \"merge_response\", ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n const res = await runWorker(msg as ProcessRequest);\n parentPort!.postMessage(res);\n } else if (msg.type === \"merge_request\") {\n const res = merge(msg as MergeRequest);\n parentPort!.postMessage(res);\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_B0_MIN","UTF8_B0_2B_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","CHAR_ZERO_11","CHAR_ZERO_111","MIN_WORKERS","MAX_WORKERS","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_IDX","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_IDX","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","stations","createReadStream","bufI","tempI","leaf","chunk","N","tempV","parseDouble","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n * \n * @remarks\n * \n * Changing this value affects the `count` and \n * `sum` values used for calculating a station's\n * average temperature. \n * \n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n * \n * @remarks\n * \n * Changing this value affects the indexing of trie nodes.\n * \n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n * \n * @remarks\n * \n * Changing this value affects the indexing of trie nodes.\n * \n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n * \n * @remarks\n * \n * Changing this value affects the `min`, `max` and `sum` values \n * used for calculating a station's min, max and avg \n * temperatures, respectively. \n * \n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n * \n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n * \n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n * \n * @remarks\n * \n * This limit should be sufficient for most use cases. \n * However, feel free to adjust up or down as needed. \n * \n * There is not much basis for the current value.\n * Development was done with at most 8 workers and \n * a reasonable input file, with memory never exceeding \n * 20 MiB total across all workers.\n * \n * In theory, the challenge constraints allow for input \n * files that would require each worker using upwards of \n * 800 MiB; 10K stations with completely unique 100 byte names, \n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n// \n// Controls trie behavior such as the default \n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_PTR_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_XPTR_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_BYTE_MIN);\n let child = trie[index + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index + TRIE_PTR_IDX_IDX] = child;\n // Initialize node\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node + TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TRIE_NODE_ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_PTR_IDX_IDX];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_PTR_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai + TRIE_PTR_IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TRIE_XPTR_ID_IDX] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { type: \"merge_response\", ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n const res = await runWorker(msg as ProcessRequest);\n parentPort!.postMessage(res);\n } else if (msg.type === \"merge_request\") {\n const res = merge(msg as MergeRequest);\n parentPort!.postMessage(res);\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","CHAR_ZERO_11","CHAR_ZERO_111","MIN_WORKERS","MAX_WORKERS","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_IDX","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_IDX","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","stations","createReadStream","bufI","tempI","leaf","chunk","N","tempV","parseDouble","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/src/constants/constraints.ts b/src/main/nodejs/havelessbemore/src/constants/constraints.ts index b544d3f..ea8ffc2 100644 --- a/src/main/nodejs/havelessbemore/src/constants/constraints.ts +++ b/src/main/nodejs/havelessbemore/src/constants/constraints.ts @@ -1,18 +1,62 @@ /** - * The maximum number of entries in the file (i.e. 1 billion). + * The maximum number of entries. + * + * @remarks + * + * Changing this value affects the `count` and + * `sum` values used for calculating a station's + * average temperature. + * + * Valid values `v` satisfy the following constraints: + * - Integers where `0 < v < 2^32` + * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48 */ export const MAX_ENTRIES = 1e9; /** - * The maximum number of unique stations (i.e. 10 thousand). + * The maximum number of unique stations. + * + * @remarks + * + * Changing this value affects the indexing of trie nodes. + * + * Valid values `v` satisfy the following constraints: + * - Positive integer + * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018. */ export const MAX_STATIONS = 1e4; /** - * The maximum length in bytes of a station name (i.e. 100 bytes). + * The maximum byte length of a station name. + * + * @remarks + * + * Changing this value affects the indexing of trie nodes. + * + * Valid values `v` satisfy the following constraints: + * - Positive integer + * - {@link MAX_STATIONS} * `v` < 3,314,018. */ export const STATION_NAME_MAX_LEN = 100; +/** + * The maximum byte length of a temperature reading. + * + * @remarks + * + * Changing this value affects the `min`, `max` and `sum` values + * used for calculating a station's min, max and avg + * temperatures, respectively. + * + * Valid values `v` satisfy the following constraints: + * - Positive integer + * - `2 <= v <= 16`. + * + * Please note that valid temperatures `t` should be: + * - `-(10^(v-2)) < t < 10^(v-2)`. + */ +export const TEMPERATURE_MAX_LEN = 5; + /** * The maximum length in bytes of an entry. * @@ -22,4 +66,4 @@ export const STATION_NAME_MAX_LEN = 100; * - Temperature: 3-5 bytes * - Newline: 1 byte */ -export const ENTRY_MAX_LEN = 107; +export const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2; diff --git a/src/main/nodejs/havelessbemore/src/constants/utf8.ts b/src/main/nodejs/havelessbemore/src/constants/utf8.ts index 11d89d1..0d04938 100644 --- a/src/main/nodejs/havelessbemore/src/constants/utf8.ts +++ b/src/main/nodejs/havelessbemore/src/constants/utf8.ts @@ -28,21 +28,27 @@ export const CHAR_ZERO = 48; // "0".charCodeAt(0); // UTF-8 constants /** - * The minimum value of the first byte of a UTF-8 code point. + * The minimum value of a UTF-8 byte. * - * Ignores the control code points from U+0000 to U+001F. + * Ignores C0 control codes from U+0000 to U+001F. * - * @see {@link https://www.charset.org/utf-8 | UTF-8 Charset} + * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes} */ -export const UTF8_B0_MIN = 32; +export const UTF8_BYTE_MIN = 32; /** - * The minimum value for noninitial bytes of a UTF-8 code point. + * The maximum value of a UTF-8 byte. * * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding} */ -export const UTF8_BN_MIN = 128; +export const UTF8_BYTE_MAX = 0b11110111; +/** + * The number of possible values in a UTF-8 byte. + */ +export const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1; + +/* export const UTF8_B0_1B_LEAD = 0b00000000; export const UTF8_BN_LEAD = 0b10000000; export const UTF8_B0_2B_LEAD = 0b11000000; @@ -60,11 +66,4 @@ export const UTF8_BN_MAX = 0b10111111; export const UTF8_B0_2B_MAX = 0b11011111; export const UTF8_B0_3B_MAX = 0b11101111; export const UTF8_B0_4B_MAX = 0b11110111; -export const UTF8_B0_MAX = UTF8_B0_4B_MAX; - -export const UTF8_B0_1B_LEN = UTF8_B0_1B_MAX - UTF8_B0_MIN + 1; -export const UTF8_B0_2B_LEN = UTF8_B0_2B_MAX - UTF8_B0_MIN + 1; -export const UTF8_B0_3B_LEN = UTF8_B0_3B_MAX - UTF8_B0_MIN + 1; -export const UTF8_B0_4B_LEN = UTF8_B0_4B_MAX - UTF8_B0_MIN + 1; -export const UTF8_B0_LEN = UTF8_B0_MAX - UTF8_B0_MIN + 1; -export const UTF8_BN_LEN = UTF8_BN_MAX - UTF8_BN_MIN + 1; +*/ \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts b/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts index 202c6b2..dcee0fb 100644 --- a/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts +++ b/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts @@ -1,29 +1,42 @@ -import { UTF8_B0_2B_LEN } from "./utf8"; +import { UTF8_BYTE_SPAN } from "./utf8"; -// Configurable constants +// Configurable constants. +// +// Controls trie behavior such as the default +// allocated size and the growth factor when resizing. /** * The default initial size of a trie. */ -export const TRIE_DEFAULT_SIZE = 524288; // 2 MiB +export const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB /** * The growth factor for resizing a trie (Approx. Phi) */ export const TRIE_GROWTH_FACTOR = 1.6180339887; -// Internal trie pointer +// Trie pointer +// +// A pointer can point to either a trie node or a trie redirect. +// They can be differentiated by the destination's ID value: +// - If the ID matches the trie's ID, then it's a trie node. +// - Otherwise, it's a trie redirect. +// The memory location the pointer points to. export const TRIE_PTR_IDX_IDX = 0; export const TRIE_PTR_IDX_MEM = 1; export const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM; -// Cross-trie pointer (aka redirect) +// Trie redirect (aka cross-trie pointer) +// +// Points to a memory location in a different trie. +// The different trie's ID. export const TRIE_XPTR_ID_IDX = 0; export const TRIE_XPTR_ID_MEM = 1; +// The memory location of the trie node in the different trie. export const TRIE_XPTR_IDX_IDX = 1; export const TRIE_XPTR_IDX_MEM = 1; @@ -31,14 +44,17 @@ export const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM; // Trie node +// The trie's ID export const TRIE_NODE_ID_IDX = 0; export const TRIE_NODE_ID_MEM = 1; +// The node's value export const TRIE_NODE_VALUE_IDX = 1; export const TRIE_NODE_VALUE_MEM = 1; +// The node's children pointers export const TRIE_NODE_CHILDREN_IDX = 2; -export const TRIE_NODE_CHILDREN_LEN = UTF8_B0_2B_LEN; +export const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN; export const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN; export const TRIE_NODE_MEM = @@ -47,15 +63,19 @@ export const TRIE_NODE_MEM = // Trie /** - * Represents a null / undefined trie element. + * Represents a `null` trie element. */ export const TRIE_NULL = 0; +// The memory location for the trie's size. export const TRIE_SIZE_IDX = 0; export const TRIE_SIZE_MEM = 1; +// The memory location for the trie's root node. export const TRIE_ROOT_IDX = 1; export const TRIE_ROOT_MEM = TRIE_NODE_MEM; +// The memory location for the trie's ID (i.e. the root node's trie ID). export const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX; + export const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM; diff --git a/src/main/nodejs/havelessbemore/src/constants/workers.ts b/src/main/nodejs/havelessbemore/src/constants/workers.ts index 248e0f8..72ebbe8 100644 --- a/src/main/nodejs/havelessbemore/src/constants/workers.ts +++ b/src/main/nodejs/havelessbemore/src/constants/workers.ts @@ -5,5 +5,24 @@ export const MIN_WORKERS = 1; /** * The maximum number of web workers (inclusive). + * + * The purpose is to limit the amount of memory used, + * since each worker uses its own memory for processing. + * + * @remarks + * + * This limit should be sufficient for most use cases. + * However, feel free to adjust up or down as needed. + * + * There is not much basis for the current value. + * Development was done with at most 8 workers and + * a reasonable input file, with memory never exceeding + * 20 MiB total across all workers. + * + * In theory, the challenge constraints allow for input + * files that would require each worker using upwards of + * 800 MiB; 10K stations with completely unique 100 byte names, + * thus 1M trie nodes of ~0.85 KB each. This should be + * considered when increasing the number of workers. */ export const MAX_WORKERS = 512; diff --git a/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts b/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts index 8c27115..d9d2359 100644 --- a/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts +++ b/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts @@ -20,7 +20,7 @@ import { TRIE_NODE_CHILDREN_MEM, TRIE_NODE_CHILDREN_LEN, } from "../constants/utf8Trie"; -import { UTF8_B0_MIN } from "../constants/utf8"; +import { UTF8_BYTE_MIN } from "../constants/utf8"; export function add( trie: Int32Array, @@ -30,7 +30,7 @@ export function add( ): [Int32Array, number] { let index = TRIE_ROOT_IDX; while (min < max) { - index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN); + index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_BYTE_MIN); let child = trie[index + TRIE_PTR_IDX_IDX]; if (child === TRIE_NULL) { // Allocate node @@ -60,7 +60,7 @@ export function get( let node = TRIE_ROOT_IDX; while (min < max) { const ptr = - node + TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_B0_MIN); + node + TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_BYTE_MIN); let child = tries[trie][ptr + TRIE_PTR_IDX_IDX]; if (child === TRIE_NULL) { return undefined; @@ -221,7 +221,7 @@ export function print( } // Add the child to the stack - key[top] = numChild + UTF8_B0_MIN; + key[top] = numChild + UTF8_BYTE_MIN; stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0]; // Print value, if any From 20f3d17dc6c38801c3500350451f68c6e74b8a3e Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Thu, 23 May 2024 16:03:19 -0400 Subject: [PATCH 25/69] Format files --- .../nodejs/havelessbemore/dist/index.cjs.map | 2 +- .../nodejs/havelessbemore/dist/index.mjs.map | 2 +- .../src/constants/constraints.ts | 36 +++++++++---------- .../havelessbemore/src/constants/utf8.ts | 2 +- .../havelessbemore/src/constants/utf8Trie.ts | 4 +-- .../havelessbemore/src/constants/workers.ts | 24 ++++++------- .../havelessbemore/src/utils/utf8Trie.ts | 7 ++-- 7 files changed, 40 insertions(+), 37 deletions(-) diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs.map b/src/main/nodejs/havelessbemore/dist/index.cjs.map index 66ac565..9b1e47b 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.cjs.map @@ -1 +1 @@ -{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n * \n * @remarks\n * \n * Changing this value affects the `count` and \n * `sum` values used for calculating a station's\n * average temperature. \n * \n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n * \n * @remarks\n * \n * Changing this value affects the indexing of trie nodes.\n * \n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n * \n * @remarks\n * \n * Changing this value affects the indexing of trie nodes.\n * \n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n * \n * @remarks\n * \n * Changing this value affects the `min`, `max` and `sum` values \n * used for calculating a station's min, max and avg \n * temperatures, respectively. \n * \n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n * \n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n * \n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n * \n * @remarks\n * \n * This limit should be sufficient for most use cases. \n * However, feel free to adjust up or down as needed. \n * \n * There is not much basis for the current value.\n * Development was done with at most 8 workers and \n * a reasonable input file, with memory never exceeding \n * 20 MiB total across all workers.\n * \n * In theory, the challenge constraints allow for input \n * files that would require each worker using upwards of \n * 800 MiB; 10K stations with completely unique 100 byte names, \n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n// \n// Controls trie behavior such as the default \n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_PTR_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_XPTR_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_BYTE_MIN);\n let child = trie[index + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index + TRIE_PTR_IDX_IDX] = child;\n // Initialize node\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node + TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TRIE_NODE_ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_PTR_IDX_IDX];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_PTR_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai + TRIE_PTR_IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TRIE_XPTR_ID_IDX] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { type: \"merge_response\", ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n const res = await runWorker(msg as ProcessRequest);\n parentPort!.postMessage(res);\n } else if (msg.type === \"merge_request\") {\n const res = merge(msg as MergeRequest);\n parentPort!.postMessage(res);\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","CHAR_ZERO_11","CHAR_ZERO_111","MIN_WORKERS","MAX_WORKERS","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_IDX","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_IDX","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","stations","createReadStream","bufI","tempI","leaf","chunk","N","tempV","parseDouble","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","_documentCurrentScript","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n *\n * @remarks\n *\n * Changing this value affects the `count` and\n * `sum` values used for calculating a station's\n * average temperature.\n *\n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n *\n * @remarks\n *\n * Changing this value affects the `min`, `max` and `sum` values\n * used for calculating a station's min, max and avg\n * temperatures, respectively.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n *\n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n *\n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n *\n * @remarks\n *\n * This limit should be sufficient for most use cases.\n * However, feel free to adjust up or down as needed.\n *\n * There is not much basis for the current value.\n * Development was done with at most 8 workers and\n * a reasonable input file, with memory never exceeding\n * 20 MiB total across all workers.\n *\n * In theory, the challenge constraints allow for input\n * files that would require each worker using upwards of\n * 800 MiB; 10K stations with completely unique 100 byte names,\n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_PTR_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_XPTR_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_BYTE_MIN);\n let child = trie[index + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index + TRIE_PTR_IDX_IDX] = child;\n // Initialize node\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n TRIE_PTR_MEM * (key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TRIE_NODE_ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_PTR_IDX_IDX];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_PTR_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai + TRIE_PTR_IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TRIE_XPTR_ID_IDX] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { type: \"merge_response\", ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n const res = await runWorker(msg as ProcessRequest);\n parentPort!.postMessage(res);\n } else if (msg.type === \"merge_request\") {\n const res = merge(msg as MergeRequest);\n parentPort!.postMessage(res);\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","CHAR_ZERO_11","CHAR_ZERO_111","MIN_WORKERS","MAX_WORKERS","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_IDX","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_IDX","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","stations","createReadStream","bufI","tempI","leaf","chunk","N","tempV","parseDouble","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","_documentCurrentScript","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index 2e4f5f4..46adfb6 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1 +1 @@ -{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n * \n * @remarks\n * \n * Changing this value affects the `count` and \n * `sum` values used for calculating a station's\n * average temperature. \n * \n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n * \n * @remarks\n * \n * Changing this value affects the indexing of trie nodes.\n * \n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n * \n * @remarks\n * \n * Changing this value affects the indexing of trie nodes.\n * \n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n * \n * @remarks\n * \n * Changing this value affects the `min`, `max` and `sum` values \n * used for calculating a station's min, max and avg \n * temperatures, respectively. \n * \n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n * \n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n * \n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n * \n * @remarks\n * \n * This limit should be sufficient for most use cases. \n * However, feel free to adjust up or down as needed. \n * \n * There is not much basis for the current value.\n * Development was done with at most 8 workers and \n * a reasonable input file, with memory never exceeding \n * 20 MiB total across all workers.\n * \n * In theory, the challenge constraints allow for input \n * files that would require each worker using upwards of \n * 800 MiB; 10K stations with completely unique 100 byte names, \n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n// \n// Controls trie behavior such as the default \n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_PTR_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_XPTR_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_BYTE_MIN);\n let child = trie[index + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index + TRIE_PTR_IDX_IDX] = child;\n // Initialize node\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node + TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TRIE_NODE_ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_PTR_IDX_IDX];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_PTR_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai + TRIE_PTR_IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TRIE_XPTR_ID_IDX] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { type: \"merge_response\", ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n const res = await runWorker(msg as ProcessRequest);\n parentPort!.postMessage(res);\n } else if (msg.type === \"merge_request\") {\n const res = merge(msg as MergeRequest);\n parentPort!.postMessage(res);\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","CHAR_ZERO_11","CHAR_ZERO_111","MIN_WORKERS","MAX_WORKERS","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_IDX","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_IDX","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","stations","createReadStream","bufI","tempI","leaf","chunk","N","tempV","parseDouble","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n *\n * @remarks\n *\n * Changing this value affects the `count` and\n * `sum` values used for calculating a station's\n * average temperature.\n *\n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n *\n * @remarks\n *\n * Changing this value affects the `min`, `max` and `sum` values\n * used for calculating a station's min, max and avg\n * temperatures, respectively.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n *\n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n *\n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n *\n * @remarks\n *\n * This limit should be sufficient for most use cases.\n * However, feel free to adjust up or down as needed.\n *\n * There is not much basis for the current value.\n * Development was done with at most 8 workers and\n * a reasonable input file, with memory never exceeding\n * 20 MiB total across all workers.\n *\n * In theory, the challenge constraints allow for input\n * files that would require each worker using upwards of\n * 800 MiB; 10K stations with completely unique 100 byte names,\n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_PTR_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_XPTR_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_BYTE_MIN);\n let child = trie[index + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index + TRIE_PTR_IDX_IDX] = child;\n // Initialize node\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n TRIE_PTR_MEM * (key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TRIE_NODE_ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_PTR_IDX_IDX];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_PTR_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai + TRIE_PTR_IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TRIE_XPTR_ID_IDX] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { type: \"merge_response\", ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n const res = await runWorker(msg as ProcessRequest);\n parentPort!.postMessage(res);\n } else if (msg.type === \"merge_request\") {\n const res = merge(msg as MergeRequest);\n parentPort!.postMessage(res);\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","CHAR_ZERO_11","CHAR_ZERO_111","MIN_WORKERS","MAX_WORKERS","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_IDX","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_IDX","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","stations","createReadStream","bufI","tempI","leaf","chunk","N","tempV","parseDouble","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/src/constants/constraints.ts b/src/main/nodejs/havelessbemore/src/constants/constraints.ts index ea8ffc2..76827cb 100644 --- a/src/main/nodejs/havelessbemore/src/constants/constraints.ts +++ b/src/main/nodejs/havelessbemore/src/constants/constraints.ts @@ -1,12 +1,12 @@ /** * The maximum number of entries. - * + * * @remarks - * - * Changing this value affects the `count` and + * + * Changing this value affects the `count` and * `sum` values used for calculating a station's - * average temperature. - * + * average temperature. + * * Valid values `v` satisfy the following constraints: * - Integers where `0 < v < 2^32` * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48 @@ -15,11 +15,11 @@ export const MAX_ENTRIES = 1e9; /** * The maximum number of unique stations. - * + * * @remarks - * + * * Changing this value affects the indexing of trie nodes. - * + * * Valid values `v` satisfy the following constraints: * - Positive integer * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018. @@ -28,11 +28,11 @@ export const MAX_STATIONS = 1e4; /** * The maximum byte length of a station name. - * + * * @remarks - * + * * Changing this value affects the indexing of trie nodes. - * + * * Valid values `v` satisfy the following constraints: * - Positive integer * - {@link MAX_STATIONS} * `v` < 3,314,018. @@ -41,17 +41,17 @@ export const STATION_NAME_MAX_LEN = 100; /** * The maximum byte length of a temperature reading. - * + * * @remarks - * - * Changing this value affects the `min`, `max` and `sum` values - * used for calculating a station's min, max and avg - * temperatures, respectively. - * + * + * Changing this value affects the `min`, `max` and `sum` values + * used for calculating a station's min, max and avg + * temperatures, respectively. + * * Valid values `v` satisfy the following constraints: * - Positive integer * - `2 <= v <= 16`. - * + * * Please note that valid temperatures `t` should be: * - `-(10^(v-2)) < t < 10^(v-2)`. */ diff --git a/src/main/nodejs/havelessbemore/src/constants/utf8.ts b/src/main/nodejs/havelessbemore/src/constants/utf8.ts index 0d04938..f2d4c20 100644 --- a/src/main/nodejs/havelessbemore/src/constants/utf8.ts +++ b/src/main/nodejs/havelessbemore/src/constants/utf8.ts @@ -66,4 +66,4 @@ export const UTF8_BN_MAX = 0b10111111; export const UTF8_B0_2B_MAX = 0b11011111; export const UTF8_B0_3B_MAX = 0b11101111; export const UTF8_B0_4B_MAX = 0b11110111; -*/ \ No newline at end of file +*/ diff --git a/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts b/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts index dcee0fb..4490745 100644 --- a/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts +++ b/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts @@ -1,8 +1,8 @@ import { UTF8_BYTE_SPAN } from "./utf8"; // Configurable constants. -// -// Controls trie behavior such as the default +// +// Controls trie behavior such as the default // allocated size and the growth factor when resizing. /** diff --git a/src/main/nodejs/havelessbemore/src/constants/workers.ts b/src/main/nodejs/havelessbemore/src/constants/workers.ts index 72ebbe8..c31d359 100644 --- a/src/main/nodejs/havelessbemore/src/constants/workers.ts +++ b/src/main/nodejs/havelessbemore/src/constants/workers.ts @@ -5,23 +5,23 @@ export const MIN_WORKERS = 1; /** * The maximum number of web workers (inclusive). - * + * * The purpose is to limit the amount of memory used, * since each worker uses its own memory for processing. - * + * * @remarks - * - * This limit should be sufficient for most use cases. - * However, feel free to adjust up or down as needed. - * + * + * This limit should be sufficient for most use cases. + * However, feel free to adjust up or down as needed. + * * There is not much basis for the current value. - * Development was done with at most 8 workers and - * a reasonable input file, with memory never exceeding + * Development was done with at most 8 workers and + * a reasonable input file, with memory never exceeding * 20 MiB total across all workers. - * - * In theory, the challenge constraints allow for input - * files that would require each worker using upwards of - * 800 MiB; 10K stations with completely unique 100 byte names, + * + * In theory, the challenge constraints allow for input + * files that would require each worker using upwards of + * 800 MiB; 10K stations with completely unique 100 byte names, * thus 1M trie nodes of ~0.85 KB each. This should be * considered when increasing the number of workers. */ diff --git a/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts b/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts index d9d2359..bf706a5 100644 --- a/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts +++ b/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts @@ -30,7 +30,8 @@ export function add( ): [Int32Array, number] { let index = TRIE_ROOT_IDX; while (min < max) { - index += TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_BYTE_MIN); + index += + TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_BYTE_MIN); let child = trie[index + TRIE_PTR_IDX_IDX]; if (child === TRIE_NULL) { // Allocate node @@ -60,7 +61,9 @@ export function get( let node = TRIE_ROOT_IDX; while (min < max) { const ptr = - node + TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_BYTE_MIN); + node + + TRIE_NODE_CHILDREN_IDX + + TRIE_PTR_MEM * (key[min++] - UTF8_BYTE_MIN); let child = tries[trie][ptr + TRIE_PTR_IDX_IDX]; if (child === TRIE_NULL) { return undefined; From 4fb575b6bab130121e0f5c6c6db94016e43647a3 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Thu, 23 May 2024 16:05:19 -0400 Subject: [PATCH 26/69] Refactor index --- src/main/nodejs/havelessbemore/dist/index.cjs | 4 ++-- src/main/nodejs/havelessbemore/dist/index.cjs.map | 2 +- src/main/nodejs/havelessbemore/dist/index.mjs | 4 ++-- src/main/nodejs/havelessbemore/dist/index.mjs.map | 2 +- src/main/nodejs/havelessbemore/src/index.ts | 6 ++---- 5 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs b/src/main/nodejs/havelessbemore/dist/index.cjs index 16650ff..0582e89 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs +++ b/src/main/nodejs/havelessbemore/dist/index.cjs @@ -24,6 +24,6 @@ * SOFTWARE. */ -"use strict";var z=require("node:os"),J=require("node:url"),X=require("node:worker_threads"),P=require("node:fs"),Q=require("fs/promises"),ee=require("worker_threads"),U=typeof document<"u"?document.currentScript:null;const x=1e4,te=100,W=107,re=45,C=10,ne=59,q=48,k=32,se=216,v=16384,ae=1048576,oe=1048576,ie=152e-6,_e=v,F=11*q,b=111*q,ce=1,ue=512;function B(e,t,r){return e>t?e<=r?e:r:t}async function fe(e,t,r,I=0){const _=await Q.open(e);try{const a=(await _.stat()).size,f=Math.max(I,Math.floor(a/t)),u=Buffer.allocUnsafe(r),s=[];let o=0;for(let E=f;E=0&&ce.length&&(e=V(e,a+H)),e[y]+=H,e[_+p]=a,e[a+D]=e[G]),_=a}return[e,_]}function $(e=0,t=Ie){t=Math.max(Y,t);const r=new Int32Array(new SharedArrayBuffer(t<<2));return r[y]=Y,r[G]=e,r}function V(e,t=0){const r=e[y];t=Math.max(t,Math.ceil(r*Re));const I=new Int32Array(new SharedArrayBuffer(t<<2));for(let _=0;_e[s].length&&(e[s]=V(e[s],n+L),_.add(s)),e[s][y]+=L,e[s][o+p]=n,e[s][n+Me]=w,e[s][n+S]=R;else{const i=e[s][n+D];s!==i&&(n=e[s][n+S]),a.push([i,n,w,R])}}o+=g,l+=g}}a.splice(0,f)}while(a.length>0);return Array.from(_)}function ge(e,t,r,I,_="",a){const f=new Array(t.length+1);f[0]=[r,O+N,0];let u=0,s=!1;do{let[o,E,l]=f[u];if(l>=K){--u;continue}f[u][1]+=g,++f[u][2];let c=e[o][E+p];if(c===h)continue;const d=e[o][c+D];o!==d&&(c=e[o][c+S],o=d),t[u]=l+k,f[++u]=[o,c+N,0];const R=e[o][c+A];R!==h&&(s&&I.write(_),s=!0,a(I,t,u,R))}while(u>=0)}function De(e){const t=new ee.Worker(e);return t.on("error",r=>{throw r}),t.on("messageerror",r=>{throw r}),t.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${t.threadId} exited with code ${r}`)}),t}function j(e,t){return new Promise(r=>{e.once("message",r),e.postMessage(t)})}async function Ne(e,t,r,I=""){r=B(r,ce,ue);const _=await fe(e,r,W,_e);r=_.length;const a=new SharedArrayBuffer(x*r+1<<4),f=new Int16Array(a),u=new Int16Array(a,2),s=new Uint32Array(a,4),o=new Float64Array(a,8),E=new Array(r),l=new Array(r);for(let n=0;n{E[i.id]=i.trie});for(let n=c.length-1;n>0;--n){const i=n-1>>1,M=n;c[i]=c[i].then(()=>c[M]).then(()=>j(l[i],{type:"merge_request",a:i,b:M,counts:s,maxes:u,mins:f,sums:o,tries:E})).then(T=>{for(const m of T.ids)E[m]=T.tries[m]})}for(let n=0;nl[n].terminate());await Promise.all(c);const d=P.createWriteStream(I,{fd:I.length<1?1:void 0,flags:"a",highWaterMark:oe}),R=Buffer.allocUnsafe(te);d.write("{"),ge(E,R,0,d,", ",w),d.end(`} -`);function w(n,i,M,T){const m=Math.round(o[T<<1]/s[T<<2]);n.write(i.toString("utf8",0,M)),n.write("="),n.write((f[T<<3]/10).toFixed(1)),n.write("/"),n.write((m/10).toFixed(1)),n.write("/"),n.write((u[T<<3]/10).toFixed(1))}}async function Oe({end:e,filePath:t,id:r,start:I,counts:_,maxes:a,mins:f,sums:u}){if(I>=e)return{type:"process_response",id:r,trie:$(r,0)};let s=$(r),o=r*x+1;const E=Buffer.allocUnsafe(W),l=P.createReadStream(t,{start:I,end:e-1,highWaterMark:Ee(e-I)});let c=0,d=0,R;for await(const i of l){const M=i.length;for(let T=0;T=M?a[i]:M,++_[i>>1],u[i>>2]+=M}return{type:"process_response",id:r,trie:s}}function Xe(e,t,r){return e[t]===re?(++t,t+4>r?-(10*e[t]+e[t+2]-F):-(100*e[t]+10*e[t+1]+e[t+3]-b)):t+4>r?10*e[t]+e[t+2]-F:100*e[t]+10*e[t+1]+e[t+3]-b}function Se({a:e,b:t,tries:r,counts:I,maxes:_,mins:a,sums:f}){function u(s,o){s<<=3,o<<=3,a[s]=Math.min(a[s],a[o]),_[s]=Math.max(_[s],_[o]),I[s>>1]+=I[o>>1],f[s>>2]+=f[o>>2]}return{type:"merge_response",ids:ye(r,e,t,u),tries:r}}if(X.isMainThread){const e=J.fileURLToPath(typeof document>"u"?require("url").pathToFileURL(__filename).href:U&&U.src||new URL("index.cjs",document.baseURI).href);Ne(process.argv[2],e,z.availableParallelism())}else X.parentPort.addListener("message",async e=>{if(e.type==="process_request"){const t=await Oe(e);X.parentPort.postMessage(t)}else if(e.type==="merge_request"){const t=Se(e);X.parentPort.postMessage(t)}else throw new Error("Unknown message type")}); +"use strict";var z=require("node:os"),J=require("node:url"),X=require("node:worker_threads"),P=require("node:fs"),Q=require("fs/promises"),ee=require("worker_threads"),U=typeof document<"u"?document.currentScript:null;const x=1e4,te=100,W=107,re=45,C=10,ne=59,q=48,k=32,se=216,v=16384,ae=1048576,oe=1048576,ie=152e-6,_e=v,F=11*q,b=111*q,ce=1,ue=512;function B(e,r,t){return e>r?e<=t?e:t:r}async function fe(e,r,t,I=0){const _=await Q.open(e);try{const a=(await _.stat()).size,f=Math.max(I,Math.floor(a/r)),u=Buffer.allocUnsafe(t),s=[];let o=0;for(let E=f;E=0&&ce.length&&(e=V(e,a+H)),e[y]+=H,e[_+p]=a,e[a+D]=e[G]),_=a}return[e,_]}function $(e=0,r=Ie){r=Math.max(Y,r);const t=new Int32Array(new SharedArrayBuffer(r<<2));return t[y]=Y,t[G]=e,t}function V(e,r=0){const t=e[y];r=Math.max(r,Math.ceil(t*Re));const I=new Int32Array(new SharedArrayBuffer(r<<2));for(let _=0;_e[s].length&&(e[s]=V(e[s],n+L),_.add(s)),e[s][y]+=L,e[s][o+p]=n,e[s][n+Me]=w,e[s][n+S]=R;else{const i=e[s][n+D];s!==i&&(n=e[s][n+S]),a.push([i,n,w,R])}}o+=g,l+=g}}a.splice(0,f)}while(a.length>0);return Array.from(_)}function ge(e,r,t,I,_="",a){const f=new Array(r.length+1);f[0]=[t,O+N,0];let u=0,s=!1;do{let[o,E,l]=f[u];if(l>=K){--u;continue}f[u][1]+=g,++f[u][2];let c=e[o][E+p];if(c===h)continue;const d=e[o][c+D];o!==d&&(c=e[o][c+S],o=d),r[u]=l+k,f[++u]=[o,c+N,0];const R=e[o][c+A];R!==h&&(s&&I.write(_),s=!0,a(I,r,u,R))}while(u>=0)}function De(e){const r=new ee.Worker(e);return r.on("error",t=>{throw t}),r.on("messageerror",t=>{throw t}),r.on("exit",t=>{if(t>1||t<0)throw new Error(`Worker ${r.threadId} exited with code ${t}`)}),r}function j(e,r){return new Promise(t=>{e.once("message",t),e.postMessage(r)})}async function Ne(e,r,t,I=""){t=B(t,ce,ue);const _=await fe(e,t,W,_e);t=_.length;const a=new SharedArrayBuffer(x*t+1<<4),f=new Int16Array(a),u=new Int16Array(a,2),s=new Uint32Array(a,4),o=new Float64Array(a,8),E=new Array(t),l=new Array(t);for(let n=0;n{E[i.id]=i.trie});for(let n=c.length-1;n>0;--n){const i=n-1>>1,M=n;c[i]=c[i].then(()=>c[M]).then(()=>j(l[i],{type:"merge_request",a:i,b:M,counts:s,maxes:u,mins:f,sums:o,tries:E})).then(T=>{for(const m of T.ids)E[m]=T.tries[m]})}for(let n=0;nl[n].terminate());await Promise.all(c);const d=P.createWriteStream(I,{fd:I.length<1?1:void 0,flags:"a",highWaterMark:oe}),R=Buffer.allocUnsafe(te);d.write("{"),ge(E,R,0,d,", ",w),d.end(`} +`);function w(n,i,M,T){const m=Math.round(o[T<<1]/s[T<<2]);n.write(i.toString("utf8",0,M)),n.write("="),n.write((f[T<<3]/10).toFixed(1)),n.write("/"),n.write((m/10).toFixed(1)),n.write("/"),n.write((u[T<<3]/10).toFixed(1))}}async function Oe({end:e,filePath:r,id:t,start:I,counts:_,maxes:a,mins:f,sums:u}){if(I>=e)return{type:"process_response",id:t,trie:$(t,0)};let s=$(t),o=t*x+1;const E=Buffer.allocUnsafe(W),l=P.createReadStream(r,{start:I,end:e-1,highWaterMark:Ee(e-I)});let c=0,d=0,R;for await(const i of l){const M=i.length;for(let T=0;T=M?a[i]:M,++_[i>>1],u[i>>2]+=M}return{type:"process_response",id:t,trie:s}}function Xe(e,r,t){return e[r]===re?(++r,r+4>t?-(10*e[r]+e[r+2]-F):-(100*e[r]+10*e[r+1]+e[r+3]-b)):r+4>t?10*e[r]+e[r+2]-F:100*e[r]+10*e[r+1]+e[r+3]-b}function Se({a:e,b:r,tries:t,counts:I,maxes:_,mins:a,sums:f}){function u(s,o){s<<=3,o<<=3,a[s]=Math.min(a[s],a[o]),_[s]=Math.max(_[s],_[o]),I[s>>1]+=I[o>>1],f[s>>2]+=f[o>>2]}return{type:"merge_response",ids:ye(t,e,r,u),tries:t}}if(X.isMainThread){const e=J.fileURLToPath(typeof document>"u"?require("url").pathToFileURL(__filename).href:U&&U.src||new URL("index.cjs",document.baseURI).href);Ne(process.argv[2],e,z.availableParallelism())}else X.parentPort.addListener("message",async e=>{if(e.type==="process_request")X.parentPort.postMessage(await Oe(e));else if(e.type==="merge_request")X.parentPort.postMessage(Se(e));else throw new Error("Unknown message type")}); //# sourceMappingURL=index.cjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs.map b/src/main/nodejs/havelessbemore/dist/index.cjs.map index 9b1e47b..a3a6d50 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.cjs.map @@ -1 +1 @@ -{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n *\n * @remarks\n *\n * Changing this value affects the `count` and\n * `sum` values used for calculating a station's\n * average temperature.\n *\n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n *\n * @remarks\n *\n * Changing this value affects the `min`, `max` and `sum` values\n * used for calculating a station's min, max and avg\n * temperatures, respectively.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n *\n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n *\n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n *\n * @remarks\n *\n * This limit should be sufficient for most use cases.\n * However, feel free to adjust up or down as needed.\n *\n * There is not much basis for the current value.\n * Development was done with at most 8 workers and\n * a reasonable input file, with memory never exceeding\n * 20 MiB total across all workers.\n *\n * In theory, the challenge constraints allow for input\n * files that would require each worker using upwards of\n * 800 MiB; 10K stations with completely unique 100 byte names,\n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_PTR_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_XPTR_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_BYTE_MIN);\n let child = trie[index + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index + TRIE_PTR_IDX_IDX] = child;\n // Initialize node\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n TRIE_PTR_MEM * (key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TRIE_NODE_ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_PTR_IDX_IDX];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_PTR_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai + TRIE_PTR_IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TRIE_XPTR_ID_IDX] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { type: \"merge_response\", ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n const res = await runWorker(msg as ProcessRequest);\n parentPort!.postMessage(res);\n } else if (msg.type === \"merge_request\") {\n const res = merge(msg as MergeRequest);\n parentPort!.postMessage(res);\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","CHAR_ZERO_11","CHAR_ZERO_111","MIN_WORKERS","MAX_WORKERS","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_IDX","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_IDX","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","stations","createReadStream","bufI","tempI","leaf","chunk","N","tempV","parseDouble","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","_documentCurrentScript","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n *\n * @remarks\n *\n * Changing this value affects the `count` and\n * `sum` values used for calculating a station's\n * average temperature.\n *\n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n *\n * @remarks\n *\n * Changing this value affects the `min`, `max` and `sum` values\n * used for calculating a station's min, max and avg\n * temperatures, respectively.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n *\n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n *\n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n *\n * @remarks\n *\n * This limit should be sufficient for most use cases.\n * However, feel free to adjust up or down as needed.\n *\n * There is not much basis for the current value.\n * Development was done with at most 8 workers and\n * a reasonable input file, with memory never exceeding\n * 20 MiB total across all workers.\n *\n * In theory, the challenge constraints allow for input\n * files that would require each worker using upwards of\n * 800 MiB; 10K stations with completely unique 100 byte names,\n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_PTR_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_XPTR_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_BYTE_MIN);\n let child = trie[index + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index + TRIE_PTR_IDX_IDX] = child;\n // Initialize node\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n TRIE_PTR_MEM * (key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TRIE_NODE_ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_PTR_IDX_IDX];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_PTR_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai + TRIE_PTR_IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TRIE_XPTR_ID_IDX] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { type: \"merge_response\", ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge_request\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","CHAR_ZERO_11","CHAR_ZERO_111","MIN_WORKERS","MAX_WORKERS","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_IDX","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_IDX","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","stations","createReadStream","bufI","tempI","leaf","chunk","N","tempV","parseDouble","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","_documentCurrentScript","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index b86b1ce..3d9aab8 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -24,6 +24,6 @@ * SOFTWARE. */ -import{availableParallelism as V}from"node:os";import{fileURLToPath as z}from"node:url";import{isMainThread as j,parentPort as S}from"node:worker_threads";import{createWriteStream as J,createReadStream as Q}from"node:fs";import{open as ee}from"fs/promises";import{Worker as te}from"worker_threads";const P=1e4,re=100,x=107,ne=45,U=10,se=59,W=48,C=32,oe=216,F=16384,ae=1048576,ie=1048576,_e=152e-6,ce=F,b=11*W,k=111*W,Ee=1,fe=512;function B(e,t,r){return e>t?e<=r?e:r:t}async function Ie(e,t,r,R=0){const _=await ee(e);try{const o=(await _.stat()).size,f=Math.max(R,Math.floor(o/t)),E=Buffer.allocUnsafe(r),s=[];let a=0;for(let I=f;I=0&&ce.length&&(e=Y(e,o+H)),e[g]+=H,e[_+p]=o,e[o+N]=e[G]),_=o}return[e,_]}function v(e=0,t=le){t=Math.max(q,t);const r=new Int32Array(new SharedArrayBuffer(t<<2));return r[g]=q,r[G]=e,r}function Y(e,t=0){const r=e[g];t=Math.max(t,Math.ceil(r*ue));const R=new Int32Array(new SharedArrayBuffer(t<<2));for(let _=0;_e[s].length&&(e[s]=Y(e[s],n+L),_.add(s)),e[s][g]+=L,e[s][a+p]=n,e[s][n+Te]=w,e[s][n+X]=l;else{const i=e[s][n+N];s!==i&&(n=e[s][n+X]),o.push([i,n,w,l])}}a+=D,u+=D}}o.splice(0,f)}while(o.length>0);return Array.from(_)}function Ne(e,t,r,R,_="",o){const f=new Array(t.length+1);f[0]=[r,O+y,0];let E=0,s=!1;do{let[a,I,u]=f[E];if(u>=K){--E;continue}f[E][1]+=D,++f[E][2];let c=e[a][I+p];if(c===h)continue;const m=e[a][c+N];a!==m&&(c=e[a][c+X],a=m),t[E]=u+C,f[++E]=[a,c+y,0];const l=e[a][c+d];l!==h&&(s&&R.write(_),s=!0,o(R,t,E,l))}while(E>=0)}function ye(e){const t=new te(e);return t.on("error",r=>{throw r}),t.on("messageerror",r=>{throw r}),t.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${t.threadId} exited with code ${r}`)}),t}function $(e,t){return new Promise(r=>{e.once("message",r),e.postMessage(t)})}async function Oe(e,t,r,R=""){r=B(r,Ee,fe);const _=await Ie(e,r,x,ce);r=_.length;const o=new SharedArrayBuffer(P*r+1<<4),f=new Int16Array(o),E=new Int16Array(o,2),s=new Uint32Array(o,4),a=new Float64Array(o,8),I=new Array(r),u=new Array(r);for(let n=0;n{I[i.id]=i.trie});for(let n=c.length-1;n>0;--n){const i=n-1>>1,M=n;c[i]=c[i].then(()=>c[M]).then(()=>$(u[i],{type:"merge_request",a:i,b:M,counts:s,maxes:E,mins:f,sums:a,tries:I})).then(T=>{for(const A of T.ids)I[A]=T.tries[A]})}for(let n=0;nu[n].terminate());await Promise.all(c);const m=J(R,{fd:R.length<1?1:void 0,flags:"a",highWaterMark:ie}),l=Buffer.allocUnsafe(re);m.write("{"),Ne(I,l,0,m,", ",w),m.end(`} -`);function w(n,i,M,T){const A=Math.round(a[T<<1]/s[T<<2]);n.write(i.toString("utf8",0,M)),n.write("="),n.write((f[T<<3]/10).toFixed(1)),n.write("/"),n.write((A/10).toFixed(1)),n.write("/"),n.write((E[T<<3]/10).toFixed(1))}}async function Xe({end:e,filePath:t,id:r,start:R,counts:_,maxes:o,mins:f,sums:E}){if(R>=e)return{type:"process_response",id:r,trie:v(r,0)};let s=v(r),a=r*P+1;const I=Buffer.allocUnsafe(x),u=Q(t,{start:R,end:e-1,highWaterMark:Re(e-R)});let c=0,m=0,l;for await(const i of u){const M=i.length;for(let T=0;T=M?o[i]:M,++_[i>>1],E[i>>2]+=M}return{type:"process_response",id:r,trie:s}}function He(e,t,r){return e[t]===ne?(++t,t+4>r?-(10*e[t]+e[t+2]-b):-(100*e[t]+10*e[t+1]+e[t+3]-k)):t+4>r?10*e[t]+e[t+2]-b:100*e[t]+10*e[t+1]+e[t+3]-k}function Se({a:e,b:t,tries:r,counts:R,maxes:_,mins:o,sums:f}){function E(s,a){s<<=3,a<<=3,o[s]=Math.min(o[s],o[a]),_[s]=Math.max(_[s],_[a]),R[s>>1]+=R[a>>1],f[s>>2]+=f[a>>2]}return{type:"merge_response",ids:De(r,e,t,E),tries:r}}if(j){const e=z(import.meta.url);Oe(process.argv[2],e,V())}else S.addListener("message",async e=>{if(e.type==="process_request"){const t=await Xe(e);S.postMessage(t)}else if(e.type==="merge_request"){const t=Se(e);S.postMessage(t)}else throw new Error("Unknown message type")}); +import{availableParallelism as V}from"node:os";import{fileURLToPath as z}from"node:url";import{isMainThread as j,parentPort as S}from"node:worker_threads";import{createWriteStream as J,createReadStream as Q}from"node:fs";import{open as ee}from"fs/promises";import{Worker as te}from"worker_threads";const P=1e4,re=100,x=107,ne=45,U=10,se=59,W=48,C=32,oe=216,F=16384,ae=1048576,ie=1048576,_e=152e-6,ce=F,b=11*W,k=111*W,Ee=1,fe=512;function B(e,r,t){return e>r?e<=t?e:t:r}async function Ie(e,r,t,R=0){const _=await ee(e);try{const o=(await _.stat()).size,f=Math.max(R,Math.floor(o/r)),E=Buffer.allocUnsafe(t),s=[];let a=0;for(let I=f;I=0&&ce.length&&(e=Y(e,o+H)),e[g]+=H,e[_+p]=o,e[o+N]=e[G]),_=o}return[e,_]}function v(e=0,r=le){r=Math.max(q,r);const t=new Int32Array(new SharedArrayBuffer(r<<2));return t[g]=q,t[G]=e,t}function Y(e,r=0){const t=e[g];r=Math.max(r,Math.ceil(t*ue));const R=new Int32Array(new SharedArrayBuffer(r<<2));for(let _=0;_e[s].length&&(e[s]=Y(e[s],n+L),_.add(s)),e[s][g]+=L,e[s][a+p]=n,e[s][n+Te]=w,e[s][n+X]=l;else{const i=e[s][n+N];s!==i&&(n=e[s][n+X]),o.push([i,n,w,l])}}a+=D,u+=D}}o.splice(0,f)}while(o.length>0);return Array.from(_)}function Ne(e,r,t,R,_="",o){const f=new Array(r.length+1);f[0]=[t,O+y,0];let E=0,s=!1;do{let[a,I,u]=f[E];if(u>=K){--E;continue}f[E][1]+=D,++f[E][2];let c=e[a][I+p];if(c===h)continue;const m=e[a][c+N];a!==m&&(c=e[a][c+X],a=m),r[E]=u+C,f[++E]=[a,c+y,0];const l=e[a][c+d];l!==h&&(s&&R.write(_),s=!0,o(R,r,E,l))}while(E>=0)}function ye(e){const r=new te(e);return r.on("error",t=>{throw t}),r.on("messageerror",t=>{throw t}),r.on("exit",t=>{if(t>1||t<0)throw new Error(`Worker ${r.threadId} exited with code ${t}`)}),r}function $(e,r){return new Promise(t=>{e.once("message",t),e.postMessage(r)})}async function Oe(e,r,t,R=""){t=B(t,Ee,fe);const _=await Ie(e,t,x,ce);t=_.length;const o=new SharedArrayBuffer(P*t+1<<4),f=new Int16Array(o),E=new Int16Array(o,2),s=new Uint32Array(o,4),a=new Float64Array(o,8),I=new Array(t),u=new Array(t);for(let n=0;n{I[i.id]=i.trie});for(let n=c.length-1;n>0;--n){const i=n-1>>1,M=n;c[i]=c[i].then(()=>c[M]).then(()=>$(u[i],{type:"merge_request",a:i,b:M,counts:s,maxes:E,mins:f,sums:a,tries:I})).then(T=>{for(const A of T.ids)I[A]=T.tries[A]})}for(let n=0;nu[n].terminate());await Promise.all(c);const m=J(R,{fd:R.length<1?1:void 0,flags:"a",highWaterMark:ie}),l=Buffer.allocUnsafe(re);m.write("{"),Ne(I,l,0,m,", ",w),m.end(`} +`);function w(n,i,M,T){const A=Math.round(a[T<<1]/s[T<<2]);n.write(i.toString("utf8",0,M)),n.write("="),n.write((f[T<<3]/10).toFixed(1)),n.write("/"),n.write((A/10).toFixed(1)),n.write("/"),n.write((E[T<<3]/10).toFixed(1))}}async function Xe({end:e,filePath:r,id:t,start:R,counts:_,maxes:o,mins:f,sums:E}){if(R>=e)return{type:"process_response",id:t,trie:v(t,0)};let s=v(t),a=t*P+1;const I=Buffer.allocUnsafe(x),u=Q(r,{start:R,end:e-1,highWaterMark:Re(e-R)});let c=0,m=0,l;for await(const i of u){const M=i.length;for(let T=0;T=M?o[i]:M,++_[i>>1],E[i>>2]+=M}return{type:"process_response",id:t,trie:s}}function He(e,r,t){return e[r]===ne?(++r,r+4>t?-(10*e[r]+e[r+2]-b):-(100*e[r]+10*e[r+1]+e[r+3]-k)):r+4>t?10*e[r]+e[r+2]-b:100*e[r]+10*e[r+1]+e[r+3]-k}function Se({a:e,b:r,tries:t,counts:R,maxes:_,mins:o,sums:f}){function E(s,a){s<<=3,a<<=3,o[s]=Math.min(o[s],o[a]),_[s]=Math.max(_[s],_[a]),R[s>>1]+=R[a>>1],f[s>>2]+=f[a>>2]}return{type:"merge_response",ids:De(t,e,r,E),tries:t}}if(j){const e=z(import.meta.url);Oe(process.argv[2],e,V())}else S.addListener("message",async e=>{if(e.type==="process_request")S.postMessage(await Xe(e));else if(e.type==="merge_request")S.postMessage(Se(e));else throw new Error("Unknown message type")}); //# sourceMappingURL=index.mjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index 46adfb6..5ab4c08 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1 +1 @@ -{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n *\n * @remarks\n *\n * Changing this value affects the `count` and\n * `sum` values used for calculating a station's\n * average temperature.\n *\n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n *\n * @remarks\n *\n * Changing this value affects the `min`, `max` and `sum` values\n * used for calculating a station's min, max and avg\n * temperatures, respectively.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n *\n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n *\n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n *\n * @remarks\n *\n * This limit should be sufficient for most use cases.\n * However, feel free to adjust up or down as needed.\n *\n * There is not much basis for the current value.\n * Development was done with at most 8 workers and\n * a reasonable input file, with memory never exceeding\n * 20 MiB total across all workers.\n *\n * In theory, the challenge constraints allow for input\n * files that would require each worker using upwards of\n * 800 MiB; 10K stations with completely unique 100 byte names,\n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_PTR_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_XPTR_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_BYTE_MIN);\n let child = trie[index + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index + TRIE_PTR_IDX_IDX] = child;\n // Initialize node\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n TRIE_PTR_MEM * (key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TRIE_NODE_ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_PTR_IDX_IDX];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_PTR_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai + TRIE_PTR_IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TRIE_XPTR_ID_IDX] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { type: \"merge_response\", ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n const res = await runWorker(msg as ProcessRequest);\n parentPort!.postMessage(res);\n } else if (msg.type === \"merge_request\") {\n const res = merge(msg as MergeRequest);\n parentPort!.postMessage(res);\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","CHAR_ZERO_11","CHAR_ZERO_111","MIN_WORKERS","MAX_WORKERS","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_IDX","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_IDX","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","stations","createReadStream","bufI","tempI","leaf","chunk","N","tempV","parseDouble","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n *\n * @remarks\n *\n * Changing this value affects the `count` and\n * `sum` values used for calculating a station's\n * average temperature.\n *\n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n *\n * @remarks\n *\n * Changing this value affects the `min`, `max` and `sum` values\n * used for calculating a station's min, max and avg\n * temperatures, respectively.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n *\n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n *\n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n *\n * @remarks\n *\n * This limit should be sufficient for most use cases.\n * However, feel free to adjust up or down as needed.\n *\n * There is not much basis for the current value.\n * Development was done with at most 8 workers and\n * a reasonable input file, with memory never exceeding\n * 20 MiB total across all workers.\n *\n * In theory, the challenge constraints allow for input\n * files that would require each worker using upwards of\n * 800 MiB; 10K stations with completely unique 100 byte names,\n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_PTR_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_XPTR_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_BYTE_MIN);\n let child = trie[index + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index + TRIE_PTR_IDX_IDX] = child;\n // Initialize node\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n TRIE_PTR_MEM * (key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TRIE_NODE_ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_PTR_IDX_IDX];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_PTR_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai + TRIE_PTR_IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TRIE_XPTR_ID_IDX] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { type: \"merge_response\", ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge_request\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","CHAR_ZERO_11","CHAR_ZERO_111","MIN_WORKERS","MAX_WORKERS","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_IDX","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_IDX","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","stations","createReadStream","bufI","tempI","leaf","chunk","N","tempV","parseDouble","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/src/index.ts b/src/main/nodejs/havelessbemore/src/index.ts index bfefe81..4bbc0de 100644 --- a/src/main/nodejs/havelessbemore/src/index.ts +++ b/src/main/nodejs/havelessbemore/src/index.ts @@ -14,11 +14,9 @@ if (isMainThread) { } else { parentPort!.addListener("message", async (msg: Message) => { if (msg.type === "process_request") { - const res = await runWorker(msg as ProcessRequest); - parentPort!.postMessage(res); + parentPort!.postMessage(await runWorker(msg as ProcessRequest)); } else if (msg.type === "merge_request") { - const res = merge(msg as MergeRequest); - parentPort!.postMessage(res); + parentPort!.postMessage(merge(msg as MergeRequest)); } else { throw new Error("Unknown message type"); } From e80042890c2cf1c15350897bc024fa23805b04d0 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Thu, 23 May 2024 16:28:19 -0400 Subject: [PATCH 27/69] Update specs in README.md --- src/main/nodejs/havelessbemore/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/nodejs/havelessbemore/README.md b/src/main/nodejs/havelessbemore/README.md index a3545f4..76ca9dc 100644 --- a/src/main/nodejs/havelessbemore/README.md +++ b/src/main/nodejs/havelessbemore/README.md @@ -17,18 +17,18 @@ - Min: 14.5s - Avg: 15s -### Specs: +#### Specs: - Machine: - - MacBook Pro M2 - - RAM: 8 GB + - Model: MacBook Air + - Chip: Apple M2 - Cores: 8 (4 performance + 4 efficiency) + - Memory: 8 GB - OS: MacOS Sonoma -- Other +- Other: - NodeJS: v20.13.1 - - Web workers: 8 - Input file: ~13.8 GB ## Build From 1b06173184c97cf5e5b786b00c02a4d47c1c9d79 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Thu, 23 May 2024 22:23:50 -0400 Subject: [PATCH 28/69] Comment out possible constants from utf8Trie --- .../havelessbemore/src/utils/utf8Trie.ts | 33 +++++++++---------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts b/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts index bf706a5..31f7343 100644 --- a/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts +++ b/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts @@ -3,19 +3,16 @@ import { WriteStream } from "node:fs"; import { TRIE_DEFAULT_SIZE, TRIE_PTR_MEM, - TRIE_PTR_IDX_IDX, TRIE_GROWTH_FACTOR, TRIE_MEM, TRIE_ID_IDX, TRIE_NODE_CHILDREN_IDX, - TRIE_NODE_ID_IDX, TRIE_NODE_VALUE_IDX, TRIE_NULL, TRIE_ROOT_IDX, TRIE_SIZE_IDX, TRIE_XPTR_MEM, TRIE_XPTR_IDX_IDX, - TRIE_XPTR_ID_IDX, TRIE_NODE_MEM, TRIE_NODE_CHILDREN_MEM, TRIE_NODE_CHILDREN_LEN, @@ -31,8 +28,8 @@ export function add( let index = TRIE_ROOT_IDX; while (min < max) { index += - TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_BYTE_MIN); - let child = trie[index + TRIE_PTR_IDX_IDX]; + TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */(key[min++] - UTF8_BYTE_MIN); + let child = trie[index/*+ TRIE_PTR_IDX_IDX*/]; if (child === TRIE_NULL) { // Allocate node child = trie[TRIE_SIZE_IDX]; @@ -41,9 +38,9 @@ export function add( } trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM; // Attach node - trie[index + TRIE_PTR_IDX_IDX] = child; + trie[index/*+ TRIE_PTR_IDX_IDX*/] = child; // Initialize node - trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX]; + trie[child/* + TRIE_NODE_ID_IDX*/] = trie[TRIE_ID_IDX]; } index = child; } @@ -63,13 +60,13 @@ export function get( const ptr = node + TRIE_NODE_CHILDREN_IDX + - TRIE_PTR_MEM * (key[min++] - UTF8_BYTE_MIN); - let child = tries[trie][ptr + TRIE_PTR_IDX_IDX]; + /*TRIE_PTR_MEM * */(key[min++] - UTF8_BYTE_MIN); + let child = tries[trie][ptr/* + TRIE_PTR_IDX_IDX*/]; if (child === TRIE_NULL) { return undefined; } // Resolve redirect, if any - const childTrie = tries[trie][child + TRIE_NODE_ID_IDX]; + const childTrie = tries[trie][child/* + TRIE_NODE_ID_IDX*/]; if (childTrie !== trie) { child = tries[trie][child + TRIE_XPTR_IDX_IDX]; trie = childTrie; @@ -134,16 +131,16 @@ export function mergeLeft( const bn = bi + TRIE_NODE_CHILDREN_MEM; while (bi < bn) { // If right child is null - let ri = tries[bt][bi + TRIE_PTR_IDX_IDX]; + let ri = tries[bt][bi/* + TRIE_PTR_IDX_IDX*/]; if (ri !== TRIE_NULL) { // Resolve right child if redirect - const rt = tries[bt][ri + TRIE_NODE_ID_IDX]; + const rt = tries[bt][ri/*+ TRIE_NODE_ID_IDX*/]; if (bt !== rt) { ri = tries[bt][ri + TRIE_XPTR_IDX_IDX]; } // If left child is null - let li = tries[at][ai + TRIE_PTR_IDX_IDX]; + let li = tries[at][ai/*+ TRIE_PTR_IDX_IDX*/]; if (li === TRIE_NULL) { // Allocate redirect li = tries[at][TRIE_SIZE_IDX]; @@ -153,13 +150,13 @@ export function mergeLeft( } tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM; // Attach redirect - tries[at][ai + TRIE_PTR_IDX_IDX] = li; + tries[at][ai/*+ TRIE_PTR_IDX_IDX*/] = li; // Initialize redirect - tries[at][li + TRIE_XPTR_ID_IDX] = rt; + tries[at][li/* + TRIE_XPTR_ID_IDX*/] = rt; tries[at][li + TRIE_XPTR_IDX_IDX] = ri; } else { // Resolve left child if redirect - const lt = tries[at][li + TRIE_NODE_ID_IDX]; + const lt = tries[at][li/* + TRIE_NODE_ID_IDX*/]; if (at !== lt) { li = tries[at][li + TRIE_XPTR_IDX_IDX]; } @@ -211,13 +208,13 @@ export function print( ++stack[top][2]; // Check if child exists - let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX]; + let childI = tries[trieI][childPtr/* + TRIE_PTR_IDX_IDX*/]; if (childI === TRIE_NULL) { continue; } // Resolve redirect, if any - const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX]; + const childTrieI = tries[trieI][childI/* + TRIE_NODE_ID_IDX*/]; if (trieI !== childTrieI) { childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX]; trieI = childTrieI; From 955536e284b38b0effeb173e2b2a0ea353968039 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Thu, 23 May 2024 22:24:50 -0400 Subject: [PATCH 29/69] Simplify the chunk processing loop in the worker --- src/main/nodejs/havelessbemore/src/worker.ts | 47 +++++++++++--------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/src/main/nodejs/havelessbemore/src/worker.ts b/src/main/nodejs/havelessbemore/src/worker.ts index ada7600..f07f400 100644 --- a/src/main/nodejs/havelessbemore/src/worker.ts +++ b/src/main/nodejs/havelessbemore/src/worker.ts @@ -44,33 +44,40 @@ export async function run({ // For each chunk let bufI = 0; - let tempI = 0; let leaf: number; for await (const chunk of stream) { // For each byte const N = chunk.length; for (let i = 0; i < N; ++i) { - if (chunk[i] === CHAR_SEMICOLON) { - // If semicolon - tempI = bufI; - } else if (chunk[i] !== CHAR_NEWLINE) { - // If not newline + // If not newline + if (chunk[i] !== CHAR_NEWLINE) { buffer[bufI++] = chunk[i]; + continue; + } + + // Get semicolon + let semI = bufI - 4; + if (buffer[semI - 2] === CHAR_SEMICOLON) { + semI -= 2; + } else if (buffer[semI - 1] === CHAR_SEMICOLON) { + semI -= 1; + } + + // Get temperature + const tempV = parseDouble(buffer, semI + 1, bufI); + bufI = 0; + + // Add the station's name to the trie and get leaf index + [trie, leaf] = add(trie, buffer, 0, semI); + + // If the station existed + if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) { + // Update the station's value + updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV); } else { - // Get temperature - const tempV = parseDouble(buffer, tempI, bufI); - bufI = 0; - // Add the station's name to the trie and get leaf index - [trie, leaf] = add(trie, buffer, 0, tempI); - // If the station existed - if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) { - // Update the station's value - updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV); - } else { - // Add the new station's value - trie[leaf + TRIE_NODE_VALUE_IDX] = stations; - newStation(stations++, tempV); - } + // Add the new station's value + trie[leaf + TRIE_NODE_VALUE_IDX] = stations; + newStation(stations++, tempV); } } } From cbfb74d538727ca1d67f84bc768457087f1d51aa Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Thu, 23 May 2024 22:26:46 -0400 Subject: [PATCH 30/69] Update README.md --- src/main/nodejs/havelessbemore/README.md | 2 +- src/main/nodejs/havelessbemore/dist/index.cjs | 4 ++-- src/main/nodejs/havelessbemore/dist/index.cjs.map | 2 +- src/main/nodejs/havelessbemore/dist/index.mjs | 4 ++-- src/main/nodejs/havelessbemore/dist/index.mjs.map | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/nodejs/havelessbemore/README.md b/src/main/nodejs/havelessbemore/README.md index 76ca9dc..10bbb1d 100644 --- a/src/main/nodejs/havelessbemore/README.md +++ b/src/main/nodejs/havelessbemore/README.md @@ -14,7 +14,7 @@ ### Results -- Min: 14.5s +- Min: 13.9s - Avg: 15s #### Specs: diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs b/src/main/nodejs/havelessbemore/dist/index.cjs index 0582e89..33d1439 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs +++ b/src/main/nodejs/havelessbemore/dist/index.cjs @@ -24,6 +24,6 @@ * SOFTWARE. */ -"use strict";var z=require("node:os"),J=require("node:url"),X=require("node:worker_threads"),P=require("node:fs"),Q=require("fs/promises"),ee=require("worker_threads"),U=typeof document<"u"?document.currentScript:null;const x=1e4,te=100,W=107,re=45,C=10,ne=59,q=48,k=32,se=216,v=16384,ae=1048576,oe=1048576,ie=152e-6,_e=v,F=11*q,b=111*q,ce=1,ue=512;function B(e,r,t){return e>r?e<=t?e:t:r}async function fe(e,r,t,I=0){const _=await Q.open(e);try{const a=(await _.stat()).size,f=Math.max(I,Math.floor(a/r)),u=Buffer.allocUnsafe(t),s=[];let o=0;for(let E=f;E=0&&ce.length&&(e=V(e,a+H)),e[y]+=H,e[_+p]=a,e[a+D]=e[G]),_=a}return[e,_]}function $(e=0,r=Ie){r=Math.max(Y,r);const t=new Int32Array(new SharedArrayBuffer(r<<2));return t[y]=Y,t[G]=e,t}function V(e,r=0){const t=e[y];r=Math.max(r,Math.ceil(t*Re));const I=new Int32Array(new SharedArrayBuffer(r<<2));for(let _=0;_e[s].length&&(e[s]=V(e[s],n+L),_.add(s)),e[s][y]+=L,e[s][o+p]=n,e[s][n+Me]=w,e[s][n+S]=R;else{const i=e[s][n+D];s!==i&&(n=e[s][n+S]),a.push([i,n,w,R])}}o+=g,l+=g}}a.splice(0,f)}while(a.length>0);return Array.from(_)}function ge(e,r,t,I,_="",a){const f=new Array(r.length+1);f[0]=[t,O+N,0];let u=0,s=!1;do{let[o,E,l]=f[u];if(l>=K){--u;continue}f[u][1]+=g,++f[u][2];let c=e[o][E+p];if(c===h)continue;const d=e[o][c+D];o!==d&&(c=e[o][c+S],o=d),r[u]=l+k,f[++u]=[o,c+N,0];const R=e[o][c+A];R!==h&&(s&&I.write(_),s=!0,a(I,r,u,R))}while(u>=0)}function De(e){const r=new ee.Worker(e);return r.on("error",t=>{throw t}),r.on("messageerror",t=>{throw t}),r.on("exit",t=>{if(t>1||t<0)throw new Error(`Worker ${r.threadId} exited with code ${t}`)}),r}function j(e,r){return new Promise(t=>{e.once("message",t),e.postMessage(r)})}async function Ne(e,r,t,I=""){t=B(t,ce,ue);const _=await fe(e,t,W,_e);t=_.length;const a=new SharedArrayBuffer(x*t+1<<4),f=new Int16Array(a),u=new Int16Array(a,2),s=new Uint32Array(a,4),o=new Float64Array(a,8),E=new Array(t),l=new Array(t);for(let n=0;n{E[i.id]=i.trie});for(let n=c.length-1;n>0;--n){const i=n-1>>1,M=n;c[i]=c[i].then(()=>c[M]).then(()=>j(l[i],{type:"merge_request",a:i,b:M,counts:s,maxes:u,mins:f,sums:o,tries:E})).then(T=>{for(const m of T.ids)E[m]=T.tries[m]})}for(let n=0;nl[n].terminate());await Promise.all(c);const d=P.createWriteStream(I,{fd:I.length<1?1:void 0,flags:"a",highWaterMark:oe}),R=Buffer.allocUnsafe(te);d.write("{"),ge(E,R,0,d,", ",w),d.end(`} -`);function w(n,i,M,T){const m=Math.round(o[T<<1]/s[T<<2]);n.write(i.toString("utf8",0,M)),n.write("="),n.write((f[T<<3]/10).toFixed(1)),n.write("/"),n.write((m/10).toFixed(1)),n.write("/"),n.write((u[T<<3]/10).toFixed(1))}}async function Oe({end:e,filePath:r,id:t,start:I,counts:_,maxes:a,mins:f,sums:u}){if(I>=e)return{type:"process_response",id:t,trie:$(t,0)};let s=$(t),o=t*x+1;const E=Buffer.allocUnsafe(W),l=P.createReadStream(r,{start:I,end:e-1,highWaterMark:Ee(e-I)});let c=0,d=0,R;for await(const i of l){const M=i.length;for(let T=0;T=M?a[i]:M,++_[i>>1],u[i>>2]+=M}return{type:"process_response",id:t,trie:s}}function Xe(e,r,t){return e[r]===re?(++r,r+4>t?-(10*e[r]+e[r+2]-F):-(100*e[r]+10*e[r+1]+e[r+3]-b)):r+4>t?10*e[r]+e[r+2]-F:100*e[r]+10*e[r+1]+e[r+3]-b}function Se({a:e,b:r,tries:t,counts:I,maxes:_,mins:a,sums:f}){function u(s,o){s<<=3,o<<=3,a[s]=Math.min(a[s],a[o]),_[s]=Math.max(_[s],_[o]),I[s>>1]+=I[o>>1],f[s>>2]+=f[o>>2]}return{type:"merge_response",ids:ye(t,e,r,u),tries:t}}if(X.isMainThread){const e=J.fileURLToPath(typeof document>"u"?require("url").pathToFileURL(__filename).href:U&&U.src||new URL("index.cjs",document.baseURI).href);Ne(process.argv[2],e,z.availableParallelism())}else X.parentPort.addListener("message",async e=>{if(e.type==="process_request")X.parentPort.postMessage(await Oe(e));else if(e.type==="merge_request")X.parentPort.postMessage(Se(e));else throw new Error("Unknown message type")}); +"use strict";var j=require("node:os"),z=require("node:url"),N=require("node:worker_threads"),L=require("node:fs"),J=require("fs/promises"),Q=require("worker_threads"),X=typeof document<"u"?document.currentScript:null;const U=1e4,ee=100,x=107,te=45,P=10,C=59,W=48,q=32,re=216,k=16384,ne=1048576,se=1048576,ae=152e-6,oe=k,v=11*W,F=111*W,ie=1,_e=512;function B(e,n,r){return e>n?e<=r?e:r:n}async function ce(e,n,r,l=0){const i=await J.open(e);try{const a=(await i.stat()).size,f=Math.max(l,Math.floor(a/n)),u=Buffer.allocUnsafe(r),s=[];let o=0;for(let c=f;c=0&&_e.length&&(e=$(e,a+S)),e[y]+=S,e[i]=a,e[a]=e[Z]),i=a}return[e,i]}function Y(e=0,n=Ee){n=Math.max(G,n);const r=new Int32Array(new SharedArrayBuffer(n<<2));return r[y]=G,r[Z]=e,r}function $(e,n=0){const r=e[y];n=Math.max(n,Math.ceil(r*fe));const l=new Int32Array(new SharedArrayBuffer(n<<2));for(let i=0;ie[s].length&&(e[s]=$(e[s],t+H),i.add(s)),e[s][y]+=H,e[s][o]=t,e[s][t]=w,e[s][t+O]=R;else{const E=e[s][t];s!==E&&(t=e[s][t+O]),a.push([E,t,w,R])}}o+=D,I+=D}}a.splice(0,f)}while(a.length>0);return Array.from(i)}function ye(e,n,r,l,i="",a){const f=new Array(n.length+1);f[0]=[r,g+p,0];let u=0,s=!1;do{let[o,c,I]=f[u];if(I>=b){--u;continue}f[u][1]+=D,++f[u][2];let _=e[o][c];if(_===h)continue;const T=e[o][_];o!==T&&(_=e[o][_+O],o=T),n[u]=I+q,f[++u]=[o,_+p,0];const R=e[o][_+A];R!==h&&(s&&l.write(i),s=!0,a(l,n,u,R))}while(u>=0)}function pe(e){const n=new Q.Worker(e);return n.on("error",r=>{throw r}),n.on("messageerror",r=>{throw r}),n.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${n.threadId} exited with code ${r}`)}),n}function V(e,n){return new Promise(r=>{e.once("message",r),e.postMessage(n)})}async function ge(e,n,r,l=""){r=B(r,ie,_e);const i=await ce(e,r,x,oe);r=i.length;const a=new SharedArrayBuffer(U*r+1<<4),f=new Int16Array(a),u=new Int16Array(a,2),s=new Uint32Array(a,4),o=new Float64Array(a,8),c=new Array(r),I=new Array(r);for(let t=0;t{c[E.id]=E.trie});for(let t=_.length-1;t>0;--t){const E=t-1>>1,d=t;_[E]=_[E].then(()=>_[d]).then(()=>V(I[E],{type:"merge_request",a:E,b:d,counts:s,maxes:u,mins:f,sums:o,tries:c})).then(M=>{for(const m of M.ids)c[m]=M.tries[m]})}for(let t=0;tI[t].terminate());await Promise.all(_);const T=L.createWriteStream(l,{fd:l.length<1?1:void 0,flags:"a",highWaterMark:se}),R=Buffer.allocUnsafe(ee);T.write("{"),ye(c,R,0,T,", ",w),T.end(`} +`);function w(t,E,d,M){const m=Math.round(o[M<<1]/s[M<<2]);t.write(E.toString("utf8",0,d)),t.write("="),t.write((f[M<<3]/10).toFixed(1)),t.write("/"),t.write((m/10).toFixed(1)),t.write("/"),t.write((u[M<<3]/10).toFixed(1))}}async function Ne({end:e,filePath:n,id:r,start:l,counts:i,maxes:a,mins:f,sums:u}){if(l>=e)return{type:"process_response",id:r,trie:Y(r,0)};let s=Y(r),o=r*U+1;const c=Buffer.allocUnsafe(x),I=L.createReadStream(n,{start:l,end:e-1,highWaterMark:ue(e-l)});let _=0,T;for await(const t of I){const E=t.length;for(let d=0;d=E?a[t]:E,++i[t>>1],u[t>>2]+=E}return{type:"process_response",id:r,trie:s}}function De(e,n,r){return e[n]===te?(++n,n+4>r?-(10*e[n]+e[n+2]-v):-(100*e[n]+10*e[n+1]+e[n+3]-F)):n+4>r?10*e[n]+e[n+2]-v:100*e[n]+10*e[n+1]+e[n+3]-F}function Oe({a:e,b:n,tries:r,counts:l,maxes:i,mins:a,sums:f}){function u(s,o){s<<=3,o<<=3,a[s]=Math.min(a[s],a[o]),i[s]=Math.max(i[s],i[o]),l[s>>1]+=l[o>>1],f[s>>2]+=f[o>>2]}return{type:"merge_response",ids:Ae(r,e,n,u),tries:r}}if(N.isMainThread){const e=z.fileURLToPath(typeof document>"u"?require("url").pathToFileURL(__filename).href:X&&X.src||new URL("index.cjs",document.baseURI).href);ge(process.argv[2],e,j.availableParallelism())}else N.parentPort.addListener("message",async e=>{if(e.type==="process_request")N.parentPort.postMessage(await Ne(e));else if(e.type==="merge_request")N.parentPort.postMessage(Oe(e));else throw new Error("Unknown message type")}); //# sourceMappingURL=index.cjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs.map b/src/main/nodejs/havelessbemore/dist/index.cjs.map index a3a6d50..3e409eb 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.cjs.map @@ -1 +1 @@ -{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n *\n * @remarks\n *\n * Changing this value affects the `count` and\n * `sum` values used for calculating a station's\n * average temperature.\n *\n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n *\n * @remarks\n *\n * Changing this value affects the `min`, `max` and `sum` values\n * used for calculating a station's min, max and avg\n * temperatures, respectively.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n *\n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n *\n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n *\n * @remarks\n *\n * This limit should be sufficient for most use cases.\n * However, feel free to adjust up or down as needed.\n *\n * There is not much basis for the current value.\n * Development was done with at most 8 workers and\n * a reasonable input file, with memory never exceeding\n * 20 MiB total across all workers.\n *\n * In theory, the challenge constraints allow for input\n * files that would require each worker using upwards of\n * 800 MiB; 10K stations with completely unique 100 byte names,\n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_PTR_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_XPTR_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_BYTE_MIN);\n let child = trie[index + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index + TRIE_PTR_IDX_IDX] = child;\n // Initialize node\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n TRIE_PTR_MEM * (key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TRIE_NODE_ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_PTR_IDX_IDX];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_PTR_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai + TRIE_PTR_IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TRIE_XPTR_ID_IDX] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { type: \"merge_response\", ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge_request\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","CHAR_ZERO_11","CHAR_ZERO_111","MIN_WORKERS","MAX_WORKERS","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_IDX","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_IDX","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","stations","createReadStream","bufI","tempI","leaf","chunk","N","tempV","parseDouble","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","_documentCurrentScript","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n *\n * @remarks\n *\n * Changing this value affects the `count` and\n * `sum` values used for calculating a station's\n * average temperature.\n *\n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n *\n * @remarks\n *\n * Changing this value affects the `min`, `max` and `sum` values\n * used for calculating a station's min, max and avg\n * temperatures, respectively.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n *\n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n *\n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n *\n * @remarks\n *\n * This limit should be sufficient for most use cases.\n * However, feel free to adjust up or down as needed.\n *\n * There is not much basis for the current value.\n * Development was done with at most 8 workers and\n * a reasonable input file, with memory never exceeding\n * 20 MiB total across all workers.\n *\n * In theory, the challenge constraints allow for input\n * files that would require each worker using upwards of\n * 800 MiB; 10K stations with completely unique 100 byte names,\n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */(key[min++] - UTF8_BYTE_MIN);\n let child = trie[index/*+ TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index/*+ TRIE_PTR_IDX_IDX*/] = child;\n // Initialize node\n trie[child/* + TRIE_NODE_ID_IDX*/] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n /*TRIE_PTR_MEM * */(key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr/* + TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child/* + TRIE_NODE_ID_IDX*/];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi/* + TRIE_PTR_IDX_IDX*/];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri/*+ TRIE_NODE_ID_IDX*/];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai/*+ TRIE_PTR_IDX_IDX*/];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai/*+ TRIE_PTR_IDX_IDX*/] = li;\n // Initialize redirect\n tries[at][li/* + TRIE_XPTR_ID_IDX*/] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li/* + TRIE_NODE_ID_IDX*/];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr/* + TRIE_PTR_IDX_IDX*/];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI/* + TRIE_NODE_ID_IDX*/];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CHAR_NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 4;\n if (buffer[semI - 2] === CHAR_SEMICOLON) {\n semI -= 2;\n } else if (buffer[semI - 1] === CHAR_SEMICOLON) {\n semI -= 1;\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { type: \"merge_response\", ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge_request\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","CHAR_ZERO_11","CHAR_ZERO_111","MIN_WORKERS","MAX_WORKERS","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","stations","createReadStream","bufI","leaf","chunk","N","semI","tempV","parseDouble","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","_documentCurrentScript","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index 3d9aab8..e4a242b 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -24,6 +24,6 @@ * SOFTWARE. */ -import{availableParallelism as V}from"node:os";import{fileURLToPath as z}from"node:url";import{isMainThread as j,parentPort as S}from"node:worker_threads";import{createWriteStream as J,createReadStream as Q}from"node:fs";import{open as ee}from"fs/promises";import{Worker as te}from"worker_threads";const P=1e4,re=100,x=107,ne=45,U=10,se=59,W=48,C=32,oe=216,F=16384,ae=1048576,ie=1048576,_e=152e-6,ce=F,b=11*W,k=111*W,Ee=1,fe=512;function B(e,r,t){return e>r?e<=t?e:t:r}async function Ie(e,r,t,R=0){const _=await ee(e);try{const o=(await _.stat()).size,f=Math.max(R,Math.floor(o/r)),E=Buffer.allocUnsafe(t),s=[];let a=0;for(let I=f;I=0&&ce.length&&(e=Y(e,o+H)),e[g]+=H,e[_+p]=o,e[o+N]=e[G]),_=o}return[e,_]}function v(e=0,r=le){r=Math.max(q,r);const t=new Int32Array(new SharedArrayBuffer(r<<2));return t[g]=q,t[G]=e,t}function Y(e,r=0){const t=e[g];r=Math.max(r,Math.ceil(t*ue));const R=new Int32Array(new SharedArrayBuffer(r<<2));for(let _=0;_e[s].length&&(e[s]=Y(e[s],n+L),_.add(s)),e[s][g]+=L,e[s][a+p]=n,e[s][n+Te]=w,e[s][n+X]=l;else{const i=e[s][n+N];s!==i&&(n=e[s][n+X]),o.push([i,n,w,l])}}a+=D,u+=D}}o.splice(0,f)}while(o.length>0);return Array.from(_)}function Ne(e,r,t,R,_="",o){const f=new Array(r.length+1);f[0]=[t,O+y,0];let E=0,s=!1;do{let[a,I,u]=f[E];if(u>=K){--E;continue}f[E][1]+=D,++f[E][2];let c=e[a][I+p];if(c===h)continue;const m=e[a][c+N];a!==m&&(c=e[a][c+X],a=m),r[E]=u+C,f[++E]=[a,c+y,0];const l=e[a][c+d];l!==h&&(s&&R.write(_),s=!0,o(R,r,E,l))}while(E>=0)}function ye(e){const r=new te(e);return r.on("error",t=>{throw t}),r.on("messageerror",t=>{throw t}),r.on("exit",t=>{if(t>1||t<0)throw new Error(`Worker ${r.threadId} exited with code ${t}`)}),r}function $(e,r){return new Promise(t=>{e.once("message",t),e.postMessage(r)})}async function Oe(e,r,t,R=""){t=B(t,Ee,fe);const _=await Ie(e,t,x,ce);t=_.length;const o=new SharedArrayBuffer(P*t+1<<4),f=new Int16Array(o),E=new Int16Array(o,2),s=new Uint32Array(o,4),a=new Float64Array(o,8),I=new Array(t),u=new Array(t);for(let n=0;n{I[i.id]=i.trie});for(let n=c.length-1;n>0;--n){const i=n-1>>1,M=n;c[i]=c[i].then(()=>c[M]).then(()=>$(u[i],{type:"merge_request",a:i,b:M,counts:s,maxes:E,mins:f,sums:a,tries:I})).then(T=>{for(const A of T.ids)I[A]=T.tries[A]})}for(let n=0;nu[n].terminate());await Promise.all(c);const m=J(R,{fd:R.length<1?1:void 0,flags:"a",highWaterMark:ie}),l=Buffer.allocUnsafe(re);m.write("{"),Ne(I,l,0,m,", ",w),m.end(`} -`);function w(n,i,M,T){const A=Math.round(a[T<<1]/s[T<<2]);n.write(i.toString("utf8",0,M)),n.write("="),n.write((f[T<<3]/10).toFixed(1)),n.write("/"),n.write((A/10).toFixed(1)),n.write("/"),n.write((E[T<<3]/10).toFixed(1))}}async function Xe({end:e,filePath:r,id:t,start:R,counts:_,maxes:o,mins:f,sums:E}){if(R>=e)return{type:"process_response",id:t,trie:v(t,0)};let s=v(t),a=t*P+1;const I=Buffer.allocUnsafe(x),u=Q(r,{start:R,end:e-1,highWaterMark:Re(e-R)});let c=0,m=0,l;for await(const i of u){const M=i.length;for(let T=0;T=M?o[i]:M,++_[i>>1],E[i>>2]+=M}return{type:"process_response",id:t,trie:s}}function He(e,r,t){return e[r]===ne?(++r,r+4>t?-(10*e[r]+e[r+2]-b):-(100*e[r]+10*e[r+1]+e[r+3]-k)):r+4>t?10*e[r]+e[r+2]-b:100*e[r]+10*e[r+1]+e[r+3]-k}function Se({a:e,b:r,tries:t,counts:R,maxes:_,mins:o,sums:f}){function E(s,a){s<<=3,a<<=3,o[s]=Math.min(o[s],o[a]),_[s]=Math.max(_[s],_[a]),R[s>>1]+=R[a>>1],f[s>>2]+=f[a>>2]}return{type:"merge_response",ids:De(t,e,r,E),tries:t}}if(j){const e=z(import.meta.url);Oe(process.argv[2],e,V())}else S.addListener("message",async e=>{if(e.type==="process_request")S.postMessage(await Xe(e));else if(e.type==="merge_request")S.postMessage(Se(e));else throw new Error("Unknown message type")}); +import{availableParallelism as $}from"node:os";import{fileURLToPath as V}from"node:url";import{isMainThread as z,parentPort as H}from"node:worker_threads";import{createWriteStream as j,createReadStream as J}from"node:fs";import{open as Q}from"fs/promises";import{Worker as ee}from"worker_threads";const X=1e4,te=100,L=107,re=45,x=10,U=59,W=48,C=32,ne=216,P=16384,oe=1048576,se=1048576,ae=152e-6,ie=P,F=11*W,k=111*W,_e=1,ce=512;function B(e,n,r){return e>n?e<=r?e:r:n}async function Ee(e,n,r,I=0){const i=await Q(e);try{const s=(await i.stat()).size,l=Math.max(I,Math.floor(s/n)),E=Buffer.allocUnsafe(r),o=[];let a=0;for(let c=l;c=0&&_e.length&&(e=v(e,s+O)),e[g]+=O,e[i]=s,e[s]=e[b]),i=s}return[e,i]}function q(e=0,n=le){n=Math.max(G,n);const r=new Int32Array(new SharedArrayBuffer(n<<2));return r[g]=G,r[b]=e,r}function v(e,n=0){const r=e[g];n=Math.max(n,Math.ceil(r*Ie));const I=new Int32Array(new SharedArrayBuffer(n<<2));for(let i=0;ie[o].length&&(e[o]=v(e[o],t+S),i.add(o)),e[o][g]+=S,e[o][a]=t,e[o][t]=w,e[o][t+D]=R;else{const f=e[o][t];o!==f&&(t=e[o][t+D]),s.push([f,t,w,R])}}a+=N,u+=N}}s.splice(0,l)}while(s.length>0);return Array.from(i)}function pe(e,n,r,I,i="",s){const l=new Array(n.length+1);l[0]=[r,y+p,0];let E=0,o=!1;do{let[a,c,u]=l[E];if(u>=K){--E;continue}l[E][1]+=N,++l[E][2];let _=e[a][c];if(_===h)continue;const T=e[a][_];a!==T&&(_=e[a][_+D],a=T),n[E]=u+C,l[++E]=[a,_+p,0];const R=e[a][_+d];R!==h&&(o&&I.write(i),o=!0,s(I,n,E,R))}while(E>=0)}function ye(e){const n=new ee(e);return n.on("error",r=>{throw r}),n.on("messageerror",r=>{throw r}),n.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${n.threadId} exited with code ${r}`)}),n}function Y(e,n){return new Promise(r=>{e.once("message",r),e.postMessage(n)})}async function Ne(e,n,r,I=""){r=B(r,_e,ce);const i=await Ee(e,r,L,ie);r=i.length;const s=new SharedArrayBuffer(X*r+1<<4),l=new Int16Array(s),E=new Int16Array(s,2),o=new Uint32Array(s,4),a=new Float64Array(s,8),c=new Array(r),u=new Array(r);for(let t=0;t{c[f.id]=f.trie});for(let t=_.length-1;t>0;--t){const f=t-1>>1,m=t;_[f]=_[f].then(()=>_[m]).then(()=>Y(u[f],{type:"merge_request",a:f,b:m,counts:o,maxes:E,mins:l,sums:a,tries:c})).then(M=>{for(const A of M.ids)c[A]=M.tries[A]})}for(let t=0;tu[t].terminate());await Promise.all(_);const T=j(I,{fd:I.length<1?1:void 0,flags:"a",highWaterMark:se}),R=Buffer.allocUnsafe(te);T.write("{"),pe(c,R,0,T,", ",w),T.end(`} +`);function w(t,f,m,M){const A=Math.round(a[M<<1]/o[M<<2]);t.write(f.toString("utf8",0,m)),t.write("="),t.write((l[M<<3]/10).toFixed(1)),t.write("/"),t.write((A/10).toFixed(1)),t.write("/"),t.write((E[M<<3]/10).toFixed(1))}}async function De({end:e,filePath:n,id:r,start:I,counts:i,maxes:s,mins:l,sums:E}){if(I>=e)return{type:"process_response",id:r,trie:q(r,0)};let o=q(r),a=r*X+1;const c=Buffer.allocUnsafe(L),u=J(n,{start:I,end:e-1,highWaterMark:fe(e-I)});let _=0,T;for await(const t of u){const f=t.length;for(let m=0;m=f?s[t]:f,++i[t>>1],E[t>>2]+=f}return{type:"process_response",id:r,trie:o}}function Oe(e,n,r){return e[n]===re?(++n,n+4>r?-(10*e[n]+e[n+2]-F):-(100*e[n]+10*e[n+1]+e[n+3]-k)):n+4>r?10*e[n]+e[n+2]-F:100*e[n]+10*e[n+1]+e[n+3]-k}function He({a:e,b:n,tries:r,counts:I,maxes:i,mins:s,sums:l}){function E(o,a){o<<=3,a<<=3,s[o]=Math.min(s[o],s[a]),i[o]=Math.max(i[o],i[a]),I[o>>1]+=I[a>>1],l[o>>2]+=l[a>>2]}return{type:"merge_response",ids:ge(r,e,n,E),tries:r}}if(z){const e=V(import.meta.url);Ne(process.argv[2],e,$())}else H.addListener("message",async e=>{if(e.type==="process_request")H.postMessage(await De(e));else if(e.type==="merge_request")H.postMessage(He(e));else throw new Error("Unknown message type")}); //# sourceMappingURL=index.mjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index 5ab4c08..3173257 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1 +1 @@ -{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n *\n * @remarks\n *\n * Changing this value affects the `count` and\n * `sum` values used for calculating a station's\n * average temperature.\n *\n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n *\n * @remarks\n *\n * Changing this value affects the `min`, `max` and `sum` values\n * used for calculating a station's min, max and avg\n * temperatures, respectively.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n *\n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n *\n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n *\n * @remarks\n *\n * This limit should be sufficient for most use cases.\n * However, feel free to adjust up or down as needed.\n *\n * There is not much basis for the current value.\n * Development was done with at most 8 workers and\n * a reasonable input file, with memory never exceeding\n * 20 MiB total across all workers.\n *\n * In theory, the challenge constraints allow for input\n * files that would require each worker using upwards of\n * 800 MiB; 10K stations with completely unique 100 byte names,\n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_PTR_IDX_IDX,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_ID_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_XPTR_ID_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + TRIE_PTR_MEM * (key[min++] - UTF8_BYTE_MIN);\n let child = trie[index + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index + TRIE_PTR_IDX_IDX] = child;\n // Initialize node\n trie[child + TRIE_NODE_ID_IDX] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n TRIE_PTR_MEM * (key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr + TRIE_PTR_IDX_IDX];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TRIE_NODE_ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TRIE_PTR_IDX_IDX];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TRIE_NODE_ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TRIE_PTR_IDX_IDX];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai + TRIE_PTR_IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TRIE_XPTR_ID_IDX] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TRIE_NODE_ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TRIE_PTR_IDX_IDX];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TRIE_NODE_ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let tempI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n if (chunk[i] === CHAR_SEMICOLON) {\n // If semicolon\n tempI = bufI;\n } else if (chunk[i] !== CHAR_NEWLINE) {\n // If not newline\n buffer[bufI++] = chunk[i];\n } else {\n // Get temperature\n const tempV = parseDouble(buffer, tempI, bufI);\n bufI = 0;\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, tempI);\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { type: \"merge_response\", ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge_request\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","CHAR_ZERO_11","CHAR_ZERO_111","MIN_WORKERS","MAX_WORKERS","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_IDX","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_IDX","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","stations","createReadStream","bufI","tempI","leaf","chunk","N","tempV","parseDouble","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n *\n * @remarks\n *\n * Changing this value affects the `count` and\n * `sum` values used for calculating a station's\n * average temperature.\n *\n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n *\n * @remarks\n *\n * Changing this value affects the `min`, `max` and `sum` values\n * used for calculating a station's min, max and avg\n * temperatures, respectively.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n *\n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n *\n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n *\n * @remarks\n *\n * This limit should be sufficient for most use cases.\n * However, feel free to adjust up or down as needed.\n *\n * There is not much basis for the current value.\n * Development was done with at most 8 workers and\n * a reasonable input file, with memory never exceeding\n * 20 MiB total across all workers.\n *\n * In theory, the challenge constraints allow for input\n * files that would require each worker using upwards of\n * 800 MiB; 10K stations with completely unique 100 byte names,\n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */(key[min++] - UTF8_BYTE_MIN);\n let child = trie[index/*+ TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index/*+ TRIE_PTR_IDX_IDX*/] = child;\n // Initialize node\n trie[child/* + TRIE_NODE_ID_IDX*/] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n /*TRIE_PTR_MEM * */(key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr/* + TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child/* + TRIE_NODE_ID_IDX*/];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi/* + TRIE_PTR_IDX_IDX*/];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri/*+ TRIE_NODE_ID_IDX*/];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai/*+ TRIE_PTR_IDX_IDX*/];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai/*+ TRIE_PTR_IDX_IDX*/] = li;\n // Initialize redirect\n tries[at][li/* + TRIE_XPTR_ID_IDX*/] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li/* + TRIE_NODE_ID_IDX*/];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr/* + TRIE_PTR_IDX_IDX*/];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI/* + TRIE_NODE_ID_IDX*/];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CHAR_NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 4;\n if (buffer[semI - 2] === CHAR_SEMICOLON) {\n semI -= 2;\n } else if (buffer[semI - 1] === CHAR_SEMICOLON) {\n semI -= 1;\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { type: \"merge_response\", ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge_request\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","CHAR_ZERO_11","CHAR_ZERO_111","MIN_WORKERS","MAX_WORKERS","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","stations","createReadStream","bufI","leaf","chunk","N","semI","tempV","parseDouble","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file From df29090a1bfc78856edd4cb20158d14b9de121d7 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Fri, 24 May 2024 14:09:25 -0400 Subject: [PATCH 31/69] Try different methods for parsing temperature --- src/main/nodejs/havelessbemore/dist/index.cjs | 4 +- .../nodejs/havelessbemore/dist/index.cjs.map | 2 +- src/main/nodejs/havelessbemore/dist/index.mjs | 4 +- .../nodejs/havelessbemore/dist/index.mjs.map | 2 +- .../havelessbemore/src/constants/stream.ts | 14 ----- .../nodejs/havelessbemore/src/utils/parse.ts | 51 +++++++++++++++++++ .../havelessbemore/src/utils/utf8Trie.ts | 30 +++++------ src/main/nodejs/havelessbemore/src/worker.ts | 15 +----- 8 files changed, 73 insertions(+), 49 deletions(-) create mode 100644 src/main/nodejs/havelessbemore/src/utils/parse.ts diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs b/src/main/nodejs/havelessbemore/dist/index.cjs index 33d1439..b9565f8 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs +++ b/src/main/nodejs/havelessbemore/dist/index.cjs @@ -24,6 +24,6 @@ * SOFTWARE. */ -"use strict";var j=require("node:os"),z=require("node:url"),N=require("node:worker_threads"),L=require("node:fs"),J=require("fs/promises"),Q=require("worker_threads"),X=typeof document<"u"?document.currentScript:null;const U=1e4,ee=100,x=107,te=45,P=10,C=59,W=48,q=32,re=216,k=16384,ne=1048576,se=1048576,ae=152e-6,oe=k,v=11*W,F=111*W,ie=1,_e=512;function B(e,n,r){return e>n?e<=r?e:r:n}async function ce(e,n,r,l=0){const i=await J.open(e);try{const a=(await i.stat()).size,f=Math.max(l,Math.floor(a/n)),u=Buffer.allocUnsafe(r),s=[];let o=0;for(let c=f;c=0&&_e.length&&(e=$(e,a+S)),e[y]+=S,e[i]=a,e[a]=e[Z]),i=a}return[e,i]}function Y(e=0,n=Ee){n=Math.max(G,n);const r=new Int32Array(new SharedArrayBuffer(n<<2));return r[y]=G,r[Z]=e,r}function $(e,n=0){const r=e[y];n=Math.max(n,Math.ceil(r*fe));const l=new Int32Array(new SharedArrayBuffer(n<<2));for(let i=0;ie[s].length&&(e[s]=$(e[s],t+H),i.add(s)),e[s][y]+=H,e[s][o]=t,e[s][t]=w,e[s][t+O]=R;else{const E=e[s][t];s!==E&&(t=e[s][t+O]),a.push([E,t,w,R])}}o+=D,I+=D}}a.splice(0,f)}while(a.length>0);return Array.from(i)}function ye(e,n,r,l,i="",a){const f=new Array(n.length+1);f[0]=[r,g+p,0];let u=0,s=!1;do{let[o,c,I]=f[u];if(I>=b){--u;continue}f[u][1]+=D,++f[u][2];let _=e[o][c];if(_===h)continue;const T=e[o][_];o!==T&&(_=e[o][_+O],o=T),n[u]=I+q,f[++u]=[o,_+p,0];const R=e[o][_+A];R!==h&&(s&&l.write(i),s=!0,a(l,n,u,R))}while(u>=0)}function pe(e){const n=new Q.Worker(e);return n.on("error",r=>{throw r}),n.on("messageerror",r=>{throw r}),n.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${n.threadId} exited with code ${r}`)}),n}function V(e,n){return new Promise(r=>{e.once("message",r),e.postMessage(n)})}async function ge(e,n,r,l=""){r=B(r,ie,_e);const i=await ce(e,r,x,oe);r=i.length;const a=new SharedArrayBuffer(U*r+1<<4),f=new Int16Array(a),u=new Int16Array(a,2),s=new Uint32Array(a,4),o=new Float64Array(a,8),c=new Array(r),I=new Array(r);for(let t=0;t{c[E.id]=E.trie});for(let t=_.length-1;t>0;--t){const E=t-1>>1,d=t;_[E]=_[E].then(()=>_[d]).then(()=>V(I[E],{type:"merge_request",a:E,b:d,counts:s,maxes:u,mins:f,sums:o,tries:c})).then(M=>{for(const m of M.ids)c[m]=M.tries[m]})}for(let t=0;tI[t].terminate());await Promise.all(_);const T=L.createWriteStream(l,{fd:l.length<1?1:void 0,flags:"a",highWaterMark:se}),R=Buffer.allocUnsafe(ee);T.write("{"),ye(c,R,0,T,", ",w),T.end(`} -`);function w(t,E,d,M){const m=Math.round(o[M<<1]/s[M<<2]);t.write(E.toString("utf8",0,d)),t.write("="),t.write((f[M<<3]/10).toFixed(1)),t.write("/"),t.write((m/10).toFixed(1)),t.write("/"),t.write((u[M<<3]/10).toFixed(1))}}async function Ne({end:e,filePath:n,id:r,start:l,counts:i,maxes:a,mins:f,sums:u}){if(l>=e)return{type:"process_response",id:r,trie:Y(r,0)};let s=Y(r),o=r*U+1;const c=Buffer.allocUnsafe(x),I=L.createReadStream(n,{start:l,end:e-1,highWaterMark:ue(e-l)});let _=0,T;for await(const t of I){const E=t.length;for(let d=0;d=E?a[t]:E,++i[t>>1],u[t>>2]+=E}return{type:"process_response",id:r,trie:s}}function De(e,n,r){return e[n]===te?(++n,n+4>r?-(10*e[n]+e[n+2]-v):-(100*e[n]+10*e[n+1]+e[n+3]-F)):n+4>r?10*e[n]+e[n+2]-v:100*e[n]+10*e[n+1]+e[n+3]-F}function Oe({a:e,b:n,tries:r,counts:l,maxes:i,mins:a,sums:f}){function u(s,o){s<<=3,o<<=3,a[s]=Math.min(a[s],a[o]),i[s]=Math.max(i[s],i[o]),l[s>>1]+=l[o>>1],f[s>>2]+=f[o>>2]}return{type:"merge_response",ids:Ae(r,e,n,u),tries:r}}if(N.isMainThread){const e=z.fileURLToPath(typeof document>"u"?require("url").pathToFileURL(__filename).href:X&&X.src||new URL("index.cjs",document.baseURI).href);ge(process.argv[2],e,j.availableParallelism())}else N.parentPort.addListener("message",async e=>{if(e.type==="process_request")N.parentPort.postMessage(await Ne(e));else if(e.type==="merge_request")N.parentPort.postMessage(Oe(e));else throw new Error("Unknown message type")}); +"use strict";var V=require("node:os"),j=require("node:url"),N=require("node:worker_threads"),L=require("node:fs"),z=require("fs/promises"),J=require("worker_threads"),X=typeof document<"u"?document.currentScript:null;const U=1e4,Q=100,x=107,ee=16384,te=1048576,re=1048576,ne=152e-6,oe=16384,se=1,ae=512,ie=45,P=10,W=59,C=48,q=32,_e=216;function k(e,n,r){return e>n?e<=r?e:r:n}async function ce(e,n,r,l=0){const i=await z.open(e);try{const s=(await i.stat()).size,f=Math.max(l,Math.floor(s/n)),u=Buffer.allocUnsafe(r),o=[];let a=0;for(let c=f;c=0&&_e.length&&(e=Z(e,s+S)),e[p]+=S,e[i]=s,e[s]=e[B]),i=s}return[e,i]}function K(e=0,n=Ee){n=Math.max(b,n);const r=new Int32Array(new SharedArrayBuffer(n<<2));return r[p]=b,r[B]=e,r}function Z(e,n=0){const r=e[p];n=Math.max(n,Math.ceil(r*fe));const l=new Int32Array(new SharedArrayBuffer(n<<2));for(let i=0;ie[o].length&&(e[o]=Z(e[o],t+H),i.add(o)),e[o][p]+=H,e[o][a]=t,e[o][t]=w,e[o][t+O]=R;else{const E=e[o][t];o!==E&&(t=e[o][t+O]),s.push([E,t,w,R])}}a+=D,I+=D}}s.splice(0,f)}while(s.length>0);return Array.from(i)}function pe(e,n,r,l,i="",s){const f=new Array(n.length+1);f[0]=[r,g+y,0];let u=0,o=!1;do{let[a,c,I]=f[u];if(I>=v){--u;continue}f[u][1]+=D,++f[u][2];let _=e[a][c];if(_===h)continue;const T=e[a][_];a!==T&&(_=e[a][_+O],a=T),n[u]=I+q,f[++u]=[a,_+y,0];const R=e[a][_+m];R!==h&&(o&&l.write(i),o=!0,s(l,n,u,R))}while(u>=0)}function ye(e){const n=new J.Worker(e);return n.on("error",r=>{throw r}),n.on("messageerror",r=>{throw r}),n.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${n.threadId} exited with code ${r}`)}),n}function G(e,n){return new Promise(r=>{e.once("message",r),e.postMessage(n)})}async function ge(e,n,r,l=""){r=k(r,se,ae);const i=await ce(e,r,x,oe);r=i.length;const s=new SharedArrayBuffer(U*r+1<<4),f=new Int16Array(s),u=new Int16Array(s,2),o=new Uint32Array(s,4),a=new Float64Array(s,8),c=new Array(r),I=new Array(r);for(let t=0;t{c[E.id]=E.trie});for(let t=_.length-1;t>0;--t){const E=t-1>>1,d=t;_[E]=_[E].then(()=>_[d]).then(()=>G(I[E],{type:"merge_request",a:E,b:d,counts:o,maxes:u,mins:f,sums:a,tries:c})).then(M=>{for(const A of M.ids)c[A]=M.tries[A]})}for(let t=0;tI[t].terminate());await Promise.all(_);const T=L.createWriteStream(l,{fd:l.length<1?1:void 0,flags:"a",highWaterMark:re}),R=Buffer.allocUnsafe(Q);T.write("{"),pe(c,R,0,T,", ",w),T.end(`} +`);function w(t,E,d,M){const A=Math.round(a[M<<1]/o[M<<2]);t.write(E.toString("utf8",0,d)),t.write("="),t.write((f[M<<3]/10).toFixed(1)),t.write("/"),t.write((A/10).toFixed(1)),t.write("/"),t.write((u[M<<3]/10).toFixed(1))}}const Y=11*C,$=111*C;function Ne(e,n,r){return e[n]===ie?(++n,n+4>r?-(10*e[n]+e[n+2]-Y):-(100*e[n]+10*e[n+1]+e[n+3]-$)):n+4>r?10*e[n]+e[n+2]-Y:100*e[n]+10*e[n+1]+e[n+3]-$}async function De({end:e,filePath:n,id:r,start:l,counts:i,maxes:s,mins:f,sums:u}){if(l>=e)return{type:"process_response",id:r,trie:K(r,0)};let o=K(r),a=r*U+1;const c=Buffer.allocUnsafe(x),I=L.createReadStream(n,{start:l,end:e-1,highWaterMark:ue(e-l)});let _=0,T;for await(const t of I){const E=t.length;for(let d=0;d=E?s[t]:E,++i[t>>1],u[t>>2]+=E}return{type:"process_response",id:r,trie:o}}function Oe({a:e,b:n,tries:r,counts:l,maxes:i,mins:s,sums:f}){function u(o,a){o<<=3,a<<=3,s[o]=Math.min(s[o],s[a]),i[o]=Math.max(i[o],i[a]),l[o>>1]+=l[a>>1],f[o>>2]+=f[a>>2]}return{type:"merge_response",ids:me(r,e,n,u),tries:r}}if(N.isMainThread){const e=j.fileURLToPath(typeof document>"u"?require("url").pathToFileURL(__filename).href:X&&X.src||new URL("index.cjs",document.baseURI).href);ge(process.argv[2],e,V.availableParallelism())}else N.parentPort.addListener("message",async e=>{if(e.type==="process_request")N.parentPort.postMessage(await De(e));else if(e.type==="merge_request")N.parentPort.postMessage(Oe(e));else throw new Error("Unknown message type")}); //# sourceMappingURL=index.cjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs.map b/src/main/nodejs/havelessbemore/dist/index.cjs.map index 3e409eb..ca13f83 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.cjs.map @@ -1 +1 @@ -{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n *\n * @remarks\n *\n * Changing this value affects the `count` and\n * `sum` values used for calculating a station's\n * average temperature.\n *\n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n *\n * @remarks\n *\n * Changing this value affects the `min`, `max` and `sum` values\n * used for calculating a station's min, max and avg\n * temperatures, respectively.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n *\n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n *\n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n *\n * @remarks\n *\n * This limit should be sufficient for most use cases.\n * However, feel free to adjust up or down as needed.\n *\n * There is not much basis for the current value.\n * Development was done with at most 8 workers and\n * a reasonable input file, with memory never exceeding\n * 20 MiB total across all workers.\n *\n * In theory, the challenge constraints allow for input\n * files that would require each worker using upwards of\n * 800 MiB; 10K stations with completely unique 100 byte names,\n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */(key[min++] - UTF8_BYTE_MIN);\n let child = trie[index/*+ TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index/*+ TRIE_PTR_IDX_IDX*/] = child;\n // Initialize node\n trie[child/* + TRIE_NODE_ID_IDX*/] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n /*TRIE_PTR_MEM * */(key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr/* + TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child/* + TRIE_NODE_ID_IDX*/];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi/* + TRIE_PTR_IDX_IDX*/];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri/*+ TRIE_NODE_ID_IDX*/];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai/*+ TRIE_PTR_IDX_IDX*/];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai/*+ TRIE_PTR_IDX_IDX*/] = li;\n // Initialize redirect\n tries[at][li/* + TRIE_XPTR_ID_IDX*/] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li/* + TRIE_NODE_ID_IDX*/];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr/* + TRIE_PTR_IDX_IDX*/];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI/* + TRIE_NODE_ID_IDX*/];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CHAR_NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 4;\n if (buffer[semI - 2] === CHAR_SEMICOLON) {\n semI -= 2;\n } else if (buffer[semI - 1] === CHAR_SEMICOLON) {\n semI -= 1;\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { type: \"merge_response\", ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge_request\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","CHAR_ZERO_11","CHAR_ZERO_111","MIN_WORKERS","MAX_WORKERS","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","stations","createReadStream","bufI","leaf","chunk","N","semI","tempV","parseDouble","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","_documentCurrentScript","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/constants/utf8.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/utils/parse.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n *\n * @remarks\n *\n * Changing this value affects the `count` and\n * `sum` values used for calculating a station's\n * average temperature.\n *\n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n *\n * @remarks\n *\n * Changing this value affects the `min`, `max` and `sum` values\n * used for calculating a station's min, max and avg\n * temperatures, respectively.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n *\n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n *\n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n *\n * @remarks\n *\n * This limit should be sufficient for most use cases.\n * However, feel free to adjust up or down as needed.\n *\n * There is not much basis for the current value.\n * Development was done with at most 8 workers and\n * a reasonable input file, with memory never exceeding\n * 20 MiB total across all workers.\n *\n * In theory, the challenge constraints allow for input\n * files that would require each worker using upwards of\n * 800 MiB; 10K stations with completely unique 100 byte names,\n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = trie[index /*+ TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index /*+ TRIE_PTR_IDX_IDX*/] = child;\n // Initialize node\n trie[child /* + TRIE_NODE_ID_IDX*/] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr /* + TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child /* + TRIE_NODE_ID_IDX*/];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi /* + TRIE_PTR_IDX_IDX*/];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri /*+ TRIE_NODE_ID_IDX*/];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai /*+ TRIE_PTR_IDX_IDX*/];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai /*+ TRIE_PTR_IDX_IDX*/] = li;\n // Initialize redirect\n tries[at][li /* + TRIE_XPTR_ID_IDX*/] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li /* + TRIE_NODE_ID_IDX*/];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr /* + TRIE_PTR_IDX_IDX*/];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI /* + TRIE_NODE_ID_IDX*/];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { CHAR_MINUS, CHAR_ZERO } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n * \n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n * \n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CHAR_MINUS);\n b[min + ~sign] = CHAR_ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n }\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n * \n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CHAR_MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { parseDouble } from \"./utils/parse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CHAR_NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 4;\n if (buffer[semI - 2] === CHAR_SEMICOLON) {\n semI -= 2;\n } else if (buffer[semI - 1] === CHAR_SEMICOLON) {\n semI -= 1;\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { type: \"merge_response\", ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge_request\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","MIN_WORKERS","MAX_WORKERS","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","CHAR_ZERO_11","CHAR_ZERO_111","parseDouble","stations","createReadStream","bufI","leaf","chunk","N","semI","tempV","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","_documentCurrentScript","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index e4a242b..62a3e53 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -24,6 +24,6 @@ * SOFTWARE. */ -import{availableParallelism as $}from"node:os";import{fileURLToPath as V}from"node:url";import{isMainThread as z,parentPort as H}from"node:worker_threads";import{createWriteStream as j,createReadStream as J}from"node:fs";import{open as Q}from"fs/promises";import{Worker as ee}from"worker_threads";const X=1e4,te=100,L=107,re=45,x=10,U=59,W=48,C=32,ne=216,P=16384,oe=1048576,se=1048576,ae=152e-6,ie=P,F=11*W,k=111*W,_e=1,ce=512;function B(e,n,r){return e>n?e<=r?e:r:n}async function Ee(e,n,r,I=0){const i=await Q(e);try{const s=(await i.stat()).size,l=Math.max(I,Math.floor(s/n)),E=Buffer.allocUnsafe(r),o=[];let a=0;for(let c=l;c=0&&_e.length&&(e=v(e,s+O)),e[g]+=O,e[i]=s,e[s]=e[b]),i=s}return[e,i]}function q(e=0,n=le){n=Math.max(G,n);const r=new Int32Array(new SharedArrayBuffer(n<<2));return r[g]=G,r[b]=e,r}function v(e,n=0){const r=e[g];n=Math.max(n,Math.ceil(r*Ie));const I=new Int32Array(new SharedArrayBuffer(n<<2));for(let i=0;ie[o].length&&(e[o]=v(e[o],t+S),i.add(o)),e[o][g]+=S,e[o][a]=t,e[o][t]=w,e[o][t+D]=R;else{const f=e[o][t];o!==f&&(t=e[o][t+D]),s.push([f,t,w,R])}}a+=N,u+=N}}s.splice(0,l)}while(s.length>0);return Array.from(i)}function pe(e,n,r,I,i="",s){const l=new Array(n.length+1);l[0]=[r,y+p,0];let E=0,o=!1;do{let[a,c,u]=l[E];if(u>=K){--E;continue}l[E][1]+=N,++l[E][2];let _=e[a][c];if(_===h)continue;const T=e[a][_];a!==T&&(_=e[a][_+D],a=T),n[E]=u+C,l[++E]=[a,_+p,0];const R=e[a][_+d];R!==h&&(o&&I.write(i),o=!0,s(I,n,E,R))}while(E>=0)}function ye(e){const n=new ee(e);return n.on("error",r=>{throw r}),n.on("messageerror",r=>{throw r}),n.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${n.threadId} exited with code ${r}`)}),n}function Y(e,n){return new Promise(r=>{e.once("message",r),e.postMessage(n)})}async function Ne(e,n,r,I=""){r=B(r,_e,ce);const i=await Ee(e,r,L,ie);r=i.length;const s=new SharedArrayBuffer(X*r+1<<4),l=new Int16Array(s),E=new Int16Array(s,2),o=new Uint32Array(s,4),a=new Float64Array(s,8),c=new Array(r),u=new Array(r);for(let t=0;t{c[f.id]=f.trie});for(let t=_.length-1;t>0;--t){const f=t-1>>1,m=t;_[f]=_[f].then(()=>_[m]).then(()=>Y(u[f],{type:"merge_request",a:f,b:m,counts:o,maxes:E,mins:l,sums:a,tries:c})).then(M=>{for(const A of M.ids)c[A]=M.tries[A]})}for(let t=0;tu[t].terminate());await Promise.all(_);const T=j(I,{fd:I.length<1?1:void 0,flags:"a",highWaterMark:se}),R=Buffer.allocUnsafe(te);T.write("{"),pe(c,R,0,T,", ",w),T.end(`} -`);function w(t,f,m,M){const A=Math.round(a[M<<1]/o[M<<2]);t.write(f.toString("utf8",0,m)),t.write("="),t.write((l[M<<3]/10).toFixed(1)),t.write("/"),t.write((A/10).toFixed(1)),t.write("/"),t.write((E[M<<3]/10).toFixed(1))}}async function De({end:e,filePath:n,id:r,start:I,counts:i,maxes:s,mins:l,sums:E}){if(I>=e)return{type:"process_response",id:r,trie:q(r,0)};let o=q(r),a=r*X+1;const c=Buffer.allocUnsafe(L),u=J(n,{start:I,end:e-1,highWaterMark:fe(e-I)});let _=0,T;for await(const t of u){const f=t.length;for(let m=0;m=f?s[t]:f,++i[t>>1],E[t>>2]+=f}return{type:"process_response",id:r,trie:o}}function Oe(e,n,r){return e[n]===re?(++n,n+4>r?-(10*e[n]+e[n+2]-F):-(100*e[n]+10*e[n+1]+e[n+3]-k)):n+4>r?10*e[n]+e[n+2]-F:100*e[n]+10*e[n+1]+e[n+3]-k}function He({a:e,b:n,tries:r,counts:I,maxes:i,mins:s,sums:l}){function E(o,a){o<<=3,a<<=3,s[o]=Math.min(s[o],s[a]),i[o]=Math.max(i[o],i[a]),I[o>>1]+=I[a>>1],l[o>>2]+=l[a>>2]}return{type:"merge_response",ids:ge(r,e,n,E),tries:r}}if(z){const e=V(import.meta.url);Ne(process.argv[2],e,$())}else H.addListener("message",async e=>{if(e.type==="process_request")H.postMessage(await De(e));else if(e.type==="merge_request")H.postMessage(He(e));else throw new Error("Unknown message type")}); +import{availableParallelism as Y}from"node:os";import{fileURLToPath as $}from"node:url";import{isMainThread as V,parentPort as H}from"node:worker_threads";import{createWriteStream as z,createReadStream as j}from"node:fs";import{open as J}from"fs/promises";import{Worker as Q}from"worker_threads";const X=1e4,tt=100,L=107,et=16384,rt=1048576,nt=1048576,ot=152e-6,st=16384,at=1,it=512,_t=45,x=10,U=59,W=48,P=32,ct=216;function C(t,n,r){return t>n?t<=r?t:r:n}async function Et(t,n,r,I=0){const i=await J(t);try{const s=(await i.stat()).size,l=Math.max(I,Math.floor(s/n)),E=Buffer.allocUnsafe(r),o=[];let a=0;for(let c=l;c=0&&_t.length&&(t=b(t,s+O)),t[p]+=O,t[i]=s,t[s]=t[B]),i=s}return[t,i]}function Z(t=0,n=lt){n=Math.max(K,n);const r=new Int32Array(new SharedArrayBuffer(n<<2));return r[p]=K,r[B]=t,r}function b(t,n=0){const r=t[p];n=Math.max(n,Math.ceil(r*It));const I=new Int32Array(new SharedArrayBuffer(n<<2));for(let i=0;it[o].length&&(t[o]=b(t[o],e+S),i.add(o)),t[o][p]+=S,t[o][a]=e,t[o][e]=w,t[o][e+D]=R;else{const f=t[o][e];o!==f&&(e=t[o][e+D]),s.push([f,e,w,R])}}a+=N,u+=N}}s.splice(0,l)}while(s.length>0);return Array.from(i)}function gt(t,n,r,I,i="",s){const l=new Array(n.length+1);l[0]=[r,y+g,0];let E=0,o=!1;do{let[a,c,u]=l[E];if(u>=F){--E;continue}l[E][1]+=N,++l[E][2];let _=t[a][c];if(_===m)continue;const T=t[a][_];a!==T&&(_=t[a][_+D],a=T),n[E]=u+P,l[++E]=[a,_+g,0];const R=t[a][_+d];R!==m&&(o&&I.write(i),o=!0,s(I,n,E,R))}while(E>=0)}function yt(t){const n=new Q(t);return n.on("error",r=>{throw r}),n.on("messageerror",r=>{throw r}),n.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${n.threadId} exited with code ${r}`)}),n}function G(t,n){return new Promise(r=>{t.once("message",r),t.postMessage(n)})}async function Nt(t,n,r,I=""){r=C(r,at,it);const i=await Et(t,r,L,st);r=i.length;const s=new SharedArrayBuffer(X*r+1<<4),l=new Int16Array(s),E=new Int16Array(s,2),o=new Uint32Array(s,4),a=new Float64Array(s,8),c=new Array(r),u=new Array(r);for(let e=0;e{c[f.id]=f.trie});for(let e=_.length-1;e>0;--e){const f=e-1>>1,h=e;_[f]=_[f].then(()=>_[h]).then(()=>G(u[f],{type:"merge_request",a:f,b:h,counts:o,maxes:E,mins:l,sums:a,tries:c})).then(M=>{for(const A of M.ids)c[A]=M.tries[A]})}for(let e=0;eu[e].terminate());await Promise.all(_);const T=z(I,{fd:I.length<1?1:void 0,flags:"a",highWaterMark:nt}),R=Buffer.allocUnsafe(tt);T.write("{"),gt(c,R,0,T,", ",w),T.end(`} +`);function w(e,f,h,M){const A=Math.round(a[M<<1]/o[M<<2]);e.write(f.toString("utf8",0,h)),e.write("="),e.write((l[M<<3]/10).toFixed(1)),e.write("/"),e.write((A/10).toFixed(1)),e.write("/"),e.write((E[M<<3]/10).toFixed(1))}}const q=11*W,v=111*W;function Dt(t,n,r){return t[n]===_t?(++n,n+4>r?-(10*t[n]+t[n+2]-q):-(100*t[n]+10*t[n+1]+t[n+3]-v)):n+4>r?10*t[n]+t[n+2]-q:100*t[n]+10*t[n+1]+t[n+3]-v}async function Ot({end:t,filePath:n,id:r,start:I,counts:i,maxes:s,mins:l,sums:E}){if(I>=t)return{type:"process_response",id:r,trie:Z(r,0)};let o=Z(r),a=r*X+1;const c=Buffer.allocUnsafe(L),u=j(n,{start:I,end:t-1,highWaterMark:ft(t-I)});let _=0,T;for await(const e of u){const f=e.length;for(let h=0;h=f?s[e]:f,++i[e>>1],E[e>>2]+=f}return{type:"process_response",id:r,trie:o}}function Ht({a:t,b:n,tries:r,counts:I,maxes:i,mins:s,sums:l}){function E(o,a){o<<=3,a<<=3,s[o]=Math.min(s[o],s[a]),i[o]=Math.max(i[o],i[a]),I[o>>1]+=I[a>>1],l[o>>2]+=l[a>>2]}return{type:"merge_response",ids:pt(r,t,n,E),tries:r}}if(V){const t=$(import.meta.url);Nt(process.argv[2],t,Y())}else H.addListener("message",async t=>{if(t.type==="process_request")H.postMessage(await Ot(t));else if(t.type==="merge_request")H.postMessage(Ht(t));else throw new Error("Unknown message type")}); //# sourceMappingURL=index.mjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index 3173257..fdd3481 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1 +1 @@ -{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/utf8.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n *\n * @remarks\n *\n * Changing this value affects the `count` and\n * `sum` values used for calculating a station's\n * average temperature.\n *\n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n *\n * @remarks\n *\n * Changing this value affects the `min`, `max` and `sum` values\n * used for calculating a station's min, max and avg\n * temperatures, respectively.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n *\n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/\n","import { CHAR_ZERO } from \"./utf8\";\n\n/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n\n// PARSE DOUBLE\n\n/**\n * Used to parse doubles from -9.9 to 9.9.\n */\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\n\n/**\n * Used to parse doubles from -99.9 to 99.9.\n */\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n *\n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n *\n * @remarks\n *\n * This limit should be sufficient for most use cases.\n * However, feel free to adjust up or down as needed.\n *\n * There is not much basis for the current value.\n * Development was done with at most 8 workers and\n * a reasonable input file, with memory never exceeding\n * 20 MiB total across all workers.\n *\n * In theory, the challenge constraints allow for input\n * files that would require each worker using upwards of\n * 800 MiB; 10K stations with completely unique 100 byte names,\n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */(key[min++] - UTF8_BYTE_MIN);\n let child = trie[index/*+ TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index/*+ TRIE_PTR_IDX_IDX*/] = child;\n // Initialize node\n trie[child/* + TRIE_NODE_ID_IDX*/] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n /*TRIE_PTR_MEM * */(key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr/* + TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child/* + TRIE_NODE_ID_IDX*/];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi/* + TRIE_PTR_IDX_IDX*/];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri/*+ TRIE_NODE_ID_IDX*/];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai/*+ TRIE_PTR_IDX_IDX*/];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai/*+ TRIE_PTR_IDX_IDX*/] = li;\n // Initialize redirect\n tries[at][li/* + TRIE_XPTR_ID_IDX*/] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li/* + TRIE_NODE_ID_IDX*/];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr/* + TRIE_PTR_IDX_IDX*/];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI/* + TRIE_NODE_ID_IDX*/];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { CHAR_MINUS } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { CHAR_ZERO_11, CHAR_ZERO_111 } from \"./constants/stream\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CHAR_NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 4;\n if (buffer[semI - 2] === CHAR_SEMICOLON) {\n semI -= 2;\n } else if (buffer[semI - 1] === CHAR_SEMICOLON) {\n semI -= 1;\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { type: \"merge_response\", ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge_request\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","CHAR_ZERO_11","CHAR_ZERO_111","MIN_WORKERS","MAX_WORKERS","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","stations","createReadStream","bufI","leaf","chunk","N","semI","tempV","parseDouble","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/constants/utf8.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/utils/parse.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n *\n * @remarks\n *\n * Changing this value affects the `count` and\n * `sum` values used for calculating a station's\n * average temperature.\n *\n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n *\n * @remarks\n *\n * Changing this value affects the `min`, `max` and `sum` values\n * used for calculating a station's min, max and avg\n * temperatures, respectively.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n *\n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n *\n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n *\n * @remarks\n *\n * This limit should be sufficient for most use cases.\n * However, feel free to adjust up or down as needed.\n *\n * There is not much basis for the current value.\n * Development was done with at most 8 workers and\n * a reasonable input file, with memory never exceeding\n * 20 MiB total across all workers.\n *\n * In theory, the challenge constraints allow for input\n * files that would require each worker using upwards of\n * 800 MiB; 10K stations with completely unique 100 byte names,\n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = trie[index /*+ TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index /*+ TRIE_PTR_IDX_IDX*/] = child;\n // Initialize node\n trie[child /* + TRIE_NODE_ID_IDX*/] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr /* + TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child /* + TRIE_NODE_ID_IDX*/];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi /* + TRIE_PTR_IDX_IDX*/];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri /*+ TRIE_NODE_ID_IDX*/];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai /*+ TRIE_PTR_IDX_IDX*/];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai /*+ TRIE_PTR_IDX_IDX*/] = li;\n // Initialize redirect\n tries[at][li /* + TRIE_XPTR_ID_IDX*/] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li /* + TRIE_NODE_ID_IDX*/];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr /* + TRIE_PTR_IDX_IDX*/];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI /* + TRIE_NODE_ID_IDX*/];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { CHAR_MINUS, CHAR_ZERO } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n * \n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n * \n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CHAR_MINUS);\n b[min + ~sign] = CHAR_ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n }\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n * \n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CHAR_MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { parseDouble } from \"./utils/parse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CHAR_NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 4;\n if (buffer[semI - 2] === CHAR_SEMICOLON) {\n semI -= 2;\n } else if (buffer[semI - 1] === CHAR_SEMICOLON) {\n semI -= 1;\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { type: \"merge_response\", ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge_request\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","MIN_WORKERS","MAX_WORKERS","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","CHAR_ZERO_11","CHAR_ZERO_111","parseDouble","stations","createReadStream","bufI","leaf","chunk","N","semI","tempV","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/src/constants/stream.ts b/src/main/nodejs/havelessbemore/src/constants/stream.ts index fee19cd..131b9c3 100644 --- a/src/main/nodejs/havelessbemore/src/constants/stream.ts +++ b/src/main/nodejs/havelessbemore/src/constants/stream.ts @@ -1,5 +1,3 @@ -import { CHAR_ZERO } from "./utf8"; - /** * The minimum value in bytes for `highWaterMark`. */ @@ -25,15 +23,3 @@ export const HIGH_WATER_MARK_RATIO = 0.000152; * The minimum size in bytes of a file chunk. */ export const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN; - -// PARSE DOUBLE - -/** - * Used to parse doubles from -9.9 to 9.9. - */ -export const CHAR_ZERO_11 = 11 * CHAR_ZERO; - -/** - * Used to parse doubles from -99.9 to 99.9. - */ -export const CHAR_ZERO_111 = 111 * CHAR_ZERO; diff --git a/src/main/nodejs/havelessbemore/src/utils/parse.ts b/src/main/nodejs/havelessbemore/src/utils/parse.ts new file mode 100644 index 0000000..95683fe --- /dev/null +++ b/src/main/nodejs/havelessbemore/src/utils/parse.ts @@ -0,0 +1,51 @@ +import { CHAR_MINUS, CHAR_ZERO } from "../constants/utf8"; + +export const CHAR_ZERO_11 = 11 * CHAR_ZERO; +export const CHAR_ZERO_111 = 111 * CHAR_ZERO; + +/** + * Converts an ASCII numeric string into an integer. + * + * Fastest. + */ +export function parseDouble(b: Buffer, min: number, max: number): number { + if (b[min] === CHAR_MINUS) { + ++min; + return min + 4 > max + ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11) + : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111); + } + return min + 4 > max + ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11 + : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111; +} + +/** + * Converts an ASCII numeric string into an integer. + * + * Second fastest. + */ +export function parseDoubleFlat(b: Buffer, min: number, max: number): number { + const sign = -(b[min] === CHAR_MINUS); + b[min + ~sign] = CHAR_ZERO; + return ( + ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) - + sign + ); + } + +/** + * Converts an ASCII numeric string into an integer without branching. + * + * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}. + * + * Slowest. + */ +export function parseDoubleQuan(b: Buffer, min: number, max: number): number { + b[min - 1] = 0; + const sign = -(b[min] === CHAR_MINUS); + const signMask = -(min + 4 >= max) & sign & 0xff000000; + let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f; + v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22); + return ((v >>> 22) ^ sign) - sign; +} diff --git a/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts b/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts index 31f7343..88ee938 100644 --- a/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts +++ b/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts @@ -28,8 +28,8 @@ export function add( let index = TRIE_ROOT_IDX; while (min < max) { index += - TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */(key[min++] - UTF8_BYTE_MIN); - let child = trie[index/*+ TRIE_PTR_IDX_IDX*/]; + TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN); + let child = trie[index /*+ TRIE_PTR_IDX_IDX*/]; if (child === TRIE_NULL) { // Allocate node child = trie[TRIE_SIZE_IDX]; @@ -38,9 +38,9 @@ export function add( } trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM; // Attach node - trie[index/*+ TRIE_PTR_IDX_IDX*/] = child; + trie[index /*+ TRIE_PTR_IDX_IDX*/] = child; // Initialize node - trie[child/* + TRIE_NODE_ID_IDX*/] = trie[TRIE_ID_IDX]; + trie[child /* + TRIE_NODE_ID_IDX*/] = trie[TRIE_ID_IDX]; } index = child; } @@ -60,13 +60,13 @@ export function get( const ptr = node + TRIE_NODE_CHILDREN_IDX + - /*TRIE_PTR_MEM * */(key[min++] - UTF8_BYTE_MIN); - let child = tries[trie][ptr/* + TRIE_PTR_IDX_IDX*/]; + /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN); + let child = tries[trie][ptr /* + TRIE_PTR_IDX_IDX*/]; if (child === TRIE_NULL) { return undefined; } // Resolve redirect, if any - const childTrie = tries[trie][child/* + TRIE_NODE_ID_IDX*/]; + const childTrie = tries[trie][child /* + TRIE_NODE_ID_IDX*/]; if (childTrie !== trie) { child = tries[trie][child + TRIE_XPTR_IDX_IDX]; trie = childTrie; @@ -131,16 +131,16 @@ export function mergeLeft( const bn = bi + TRIE_NODE_CHILDREN_MEM; while (bi < bn) { // If right child is null - let ri = tries[bt][bi/* + TRIE_PTR_IDX_IDX*/]; + let ri = tries[bt][bi /* + TRIE_PTR_IDX_IDX*/]; if (ri !== TRIE_NULL) { // Resolve right child if redirect - const rt = tries[bt][ri/*+ TRIE_NODE_ID_IDX*/]; + const rt = tries[bt][ri /*+ TRIE_NODE_ID_IDX*/]; if (bt !== rt) { ri = tries[bt][ri + TRIE_XPTR_IDX_IDX]; } // If left child is null - let li = tries[at][ai/*+ TRIE_PTR_IDX_IDX*/]; + let li = tries[at][ai /*+ TRIE_PTR_IDX_IDX*/]; if (li === TRIE_NULL) { // Allocate redirect li = tries[at][TRIE_SIZE_IDX]; @@ -150,13 +150,13 @@ export function mergeLeft( } tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM; // Attach redirect - tries[at][ai/*+ TRIE_PTR_IDX_IDX*/] = li; + tries[at][ai /*+ TRIE_PTR_IDX_IDX*/] = li; // Initialize redirect - tries[at][li/* + TRIE_XPTR_ID_IDX*/] = rt; + tries[at][li /* + TRIE_XPTR_ID_IDX*/] = rt; tries[at][li + TRIE_XPTR_IDX_IDX] = ri; } else { // Resolve left child if redirect - const lt = tries[at][li/* + TRIE_NODE_ID_IDX*/]; + const lt = tries[at][li /* + TRIE_NODE_ID_IDX*/]; if (at !== lt) { li = tries[at][li + TRIE_XPTR_IDX_IDX]; } @@ -208,13 +208,13 @@ export function print( ++stack[top][2]; // Check if child exists - let childI = tries[trieI][childPtr/* + TRIE_PTR_IDX_IDX*/]; + let childI = tries[trieI][childPtr /* + TRIE_PTR_IDX_IDX*/]; if (childI === TRIE_NULL) { continue; } // Resolve redirect, if any - const childTrieI = tries[trieI][childI/* + TRIE_NODE_ID_IDX*/]; + const childTrieI = tries[trieI][childI /* + TRIE_NODE_ID_IDX*/]; if (trieI !== childTrieI) { childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX]; trieI = childTrieI; diff --git a/src/main/nodejs/havelessbemore/src/worker.ts b/src/main/nodejs/havelessbemore/src/worker.ts index f07f400..eeab789 100644 --- a/src/main/nodejs/havelessbemore/src/worker.ts +++ b/src/main/nodejs/havelessbemore/src/worker.ts @@ -5,14 +5,13 @@ import type { ProcessResponse } from "./types/processResponse"; import { CHAR_SEMICOLON } from "./constants/utf8"; import { CHAR_NEWLINE } from "./constants/utf8"; -import { CHAR_MINUS } from "./constants/utf8"; import { ENTRY_MAX_LEN, MAX_STATIONS } from "./constants/constraints"; -import { CHAR_ZERO_11, CHAR_ZERO_111 } from "./constants/stream"; import { TRIE_NODE_VALUE_IDX, TRIE_NULL } from "./constants/utf8Trie"; import { getHighWaterMark } from "./utils/stream"; import { add, createTrie, mergeLeft } from "./utils/utf8Trie"; import { MergeRequest } from "./types/mergeRequest"; import { MergeResponse } from "./types/mergeResponse"; +import { parseDouble } from "./utils/parse"; export async function run({ end, @@ -100,18 +99,6 @@ export async function run({ return { type: "process_response", id, trie }; } -export function parseDouble(b: Buffer, min: number, max: number): number { - if (b[min] === CHAR_MINUS) { - ++min; - return min + 4 > max - ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11) - : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111); - } - return min + 4 > max - ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11 - : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111; -} - export function merge({ a, b, From dc1a881260fd10201759780701704794cb6ec56c Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Fri, 24 May 2024 14:53:44 -0400 Subject: [PATCH 32/69] Update README.md to reflect new avg --- src/main/nodejs/havelessbemore/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/nodejs/havelessbemore/README.md b/src/main/nodejs/havelessbemore/README.md index 10bbb1d..70543e6 100644 --- a/src/main/nodejs/havelessbemore/README.md +++ b/src/main/nodejs/havelessbemore/README.md @@ -15,7 +15,7 @@ ### Results - Min: 13.9s -- Avg: 15s +- Avg: 14.5s #### Specs: From fc8ed7dc9714c2177b83908392ae9125978b8688 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Fri, 24 May 2024 15:31:26 -0400 Subject: [PATCH 33/69] Format files --- .../nodejs/havelessbemore/dist/index.cjs.map | 2 +- .../nodejs/havelessbemore/dist/index.mjs.map | 2 +- .../nodejs/havelessbemore/src/utils/parse.ts | 20 +++++++++---------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs.map b/src/main/nodejs/havelessbemore/dist/index.cjs.map index ca13f83..582fad0 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.cjs.map @@ -1 +1 @@ -{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/constants/utf8.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/utils/parse.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n *\n * @remarks\n *\n * Changing this value affects the `count` and\n * `sum` values used for calculating a station's\n * average temperature.\n *\n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n *\n * @remarks\n *\n * Changing this value affects the `min`, `max` and `sum` values\n * used for calculating a station's min, max and avg\n * temperatures, respectively.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n *\n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n *\n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n *\n * @remarks\n *\n * This limit should be sufficient for most use cases.\n * However, feel free to adjust up or down as needed.\n *\n * There is not much basis for the current value.\n * Development was done with at most 8 workers and\n * a reasonable input file, with memory never exceeding\n * 20 MiB total across all workers.\n *\n * In theory, the challenge constraints allow for input\n * files that would require each worker using upwards of\n * 800 MiB; 10K stations with completely unique 100 byte names,\n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = trie[index /*+ TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index /*+ TRIE_PTR_IDX_IDX*/] = child;\n // Initialize node\n trie[child /* + TRIE_NODE_ID_IDX*/] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr /* + TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child /* + TRIE_NODE_ID_IDX*/];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi /* + TRIE_PTR_IDX_IDX*/];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri /*+ TRIE_NODE_ID_IDX*/];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai /*+ TRIE_PTR_IDX_IDX*/];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai /*+ TRIE_PTR_IDX_IDX*/] = li;\n // Initialize redirect\n tries[at][li /* + TRIE_XPTR_ID_IDX*/] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li /* + TRIE_NODE_ID_IDX*/];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr /* + TRIE_PTR_IDX_IDX*/];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI /* + TRIE_NODE_ID_IDX*/];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { CHAR_MINUS, CHAR_ZERO } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n * \n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n * \n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CHAR_MINUS);\n b[min + ~sign] = CHAR_ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n }\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n * \n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CHAR_MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { parseDouble } from \"./utils/parse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CHAR_NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 4;\n if (buffer[semI - 2] === CHAR_SEMICOLON) {\n semI -= 2;\n } else if (buffer[semI - 1] === CHAR_SEMICOLON) {\n semI -= 1;\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { type: \"merge_response\", ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge_request\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","MIN_WORKERS","MAX_WORKERS","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","CHAR_ZERO_11","CHAR_ZERO_111","parseDouble","stations","createReadStream","bufI","leaf","chunk","N","semI","tempV","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","_documentCurrentScript","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/constants/utf8.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/utils/parse.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n *\n * @remarks\n *\n * Changing this value affects the `count` and\n * `sum` values used for calculating a station's\n * average temperature.\n *\n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n *\n * @remarks\n *\n * Changing this value affects the `min`, `max` and `sum` values\n * used for calculating a station's min, max and avg\n * temperatures, respectively.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n *\n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n *\n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n *\n * @remarks\n *\n * This limit should be sufficient for most use cases.\n * However, feel free to adjust up or down as needed.\n *\n * There is not much basis for the current value.\n * Development was done with at most 8 workers and\n * a reasonable input file, with memory never exceeding\n * 20 MiB total across all workers.\n *\n * In theory, the challenge constraints allow for input\n * files that would require each worker using upwards of\n * 800 MiB; 10K stations with completely unique 100 byte names,\n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = trie[index /*+ TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index /*+ TRIE_PTR_IDX_IDX*/] = child;\n // Initialize node\n trie[child /* + TRIE_NODE_ID_IDX*/] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr /* + TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child /* + TRIE_NODE_ID_IDX*/];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi /* + TRIE_PTR_IDX_IDX*/];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri /*+ TRIE_NODE_ID_IDX*/];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai /*+ TRIE_PTR_IDX_IDX*/];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai /*+ TRIE_PTR_IDX_IDX*/] = li;\n // Initialize redirect\n tries[at][li /* + TRIE_XPTR_ID_IDX*/] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li /* + TRIE_NODE_ID_IDX*/];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr /* + TRIE_PTR_IDX_IDX*/];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI /* + TRIE_NODE_ID_IDX*/];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { CHAR_MINUS, CHAR_ZERO } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CHAR_MINUS);\n b[min + ~sign] = CHAR_ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CHAR_MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { parseDouble } from \"./utils/parse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CHAR_NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 4;\n if (buffer[semI - 2] === CHAR_SEMICOLON) {\n semI -= 2;\n } else if (buffer[semI - 1] === CHAR_SEMICOLON) {\n semI -= 1;\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { type: \"merge_response\", ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge_request\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","MIN_WORKERS","MAX_WORKERS","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","CHAR_ZERO_11","CHAR_ZERO_111","parseDouble","stations","createReadStream","bufI","leaf","chunk","N","semI","tempV","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","_documentCurrentScript","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index fdd3481..d479724 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1 +1 @@ -{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/constants/utf8.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/utils/parse.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n *\n * @remarks\n *\n * Changing this value affects the `count` and\n * `sum` values used for calculating a station's\n * average temperature.\n *\n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n *\n * @remarks\n *\n * Changing this value affects the `min`, `max` and `sum` values\n * used for calculating a station's min, max and avg\n * temperatures, respectively.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n *\n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n *\n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n *\n * @remarks\n *\n * This limit should be sufficient for most use cases.\n * However, feel free to adjust up or down as needed.\n *\n * There is not much basis for the current value.\n * Development was done with at most 8 workers and\n * a reasonable input file, with memory never exceeding\n * 20 MiB total across all workers.\n *\n * In theory, the challenge constraints allow for input\n * files that would require each worker using upwards of\n * 800 MiB; 10K stations with completely unique 100 byte names,\n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = trie[index /*+ TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index /*+ TRIE_PTR_IDX_IDX*/] = child;\n // Initialize node\n trie[child /* + TRIE_NODE_ID_IDX*/] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr /* + TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child /* + TRIE_NODE_ID_IDX*/];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi /* + TRIE_PTR_IDX_IDX*/];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri /*+ TRIE_NODE_ID_IDX*/];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai /*+ TRIE_PTR_IDX_IDX*/];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai /*+ TRIE_PTR_IDX_IDX*/] = li;\n // Initialize redirect\n tries[at][li /* + TRIE_XPTR_ID_IDX*/] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li /* + TRIE_NODE_ID_IDX*/];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr /* + TRIE_PTR_IDX_IDX*/];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI /* + TRIE_NODE_ID_IDX*/];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { CHAR_MINUS, CHAR_ZERO } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n * \n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n * \n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CHAR_MINUS);\n b[min + ~sign] = CHAR_ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n }\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n * \n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CHAR_MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { parseDouble } from \"./utils/parse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CHAR_NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 4;\n if (buffer[semI - 2] === CHAR_SEMICOLON) {\n semI -= 2;\n } else if (buffer[semI - 1] === CHAR_SEMICOLON) {\n semI -= 1;\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { type: \"merge_response\", ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge_request\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","MIN_WORKERS","MAX_WORKERS","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","CHAR_ZERO_11","CHAR_ZERO_111","parseDouble","stations","createReadStream","bufI","leaf","chunk","N","semI","tempV","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/constants/utf8.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/utils/parse.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n *\n * @remarks\n *\n * Changing this value affects the `count` and\n * `sum` values used for calculating a station's\n * average temperature.\n *\n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n *\n * @remarks\n *\n * Changing this value affects the `min`, `max` and `sum` values\n * used for calculating a station's min, max and avg\n * temperatures, respectively.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n *\n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n *\n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n *\n * @remarks\n *\n * This limit should be sufficient for most use cases.\n * However, feel free to adjust up or down as needed.\n *\n * There is not much basis for the current value.\n * Development was done with at most 8 workers and\n * a reasonable input file, with memory never exceeding\n * 20 MiB total across all workers.\n *\n * In theory, the challenge constraints allow for input\n * files that would require each worker using upwards of\n * 800 MiB; 10K stations with completely unique 100 byte names,\n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = trie[index /*+ TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index /*+ TRIE_PTR_IDX_IDX*/] = child;\n // Initialize node\n trie[child /* + TRIE_NODE_ID_IDX*/] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr /* + TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child /* + TRIE_NODE_ID_IDX*/];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi /* + TRIE_PTR_IDX_IDX*/];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri /*+ TRIE_NODE_ID_IDX*/];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai /*+ TRIE_PTR_IDX_IDX*/];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai /*+ TRIE_PTR_IDX_IDX*/] = li;\n // Initialize redirect\n tries[at][li /* + TRIE_XPTR_ID_IDX*/] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li /* + TRIE_NODE_ID_IDX*/];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr /* + TRIE_PTR_IDX_IDX*/];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI /* + TRIE_NODE_ID_IDX*/];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { CHAR_MINUS, CHAR_ZERO } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CHAR_MINUS);\n b[min + ~sign] = CHAR_ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CHAR_MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { parseDouble } from \"./utils/parse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CHAR_NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 4;\n if (buffer[semI - 2] === CHAR_SEMICOLON) {\n semI -= 2;\n } else if (buffer[semI - 1] === CHAR_SEMICOLON) {\n semI -= 1;\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { type: \"merge_response\", ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge_request\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","MIN_WORKERS","MAX_WORKERS","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","CHAR_ZERO_11","CHAR_ZERO_111","parseDouble","stations","createReadStream","bufI","leaf","chunk","N","semI","tempV","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/src/utils/parse.ts b/src/main/nodejs/havelessbemore/src/utils/parse.ts index 95683fe..ac897b5 100644 --- a/src/main/nodejs/havelessbemore/src/utils/parse.ts +++ b/src/main/nodejs/havelessbemore/src/utils/parse.ts @@ -5,7 +5,7 @@ export const CHAR_ZERO_111 = 111 * CHAR_ZERO; /** * Converts an ASCII numeric string into an integer. - * + * * Fastest. */ export function parseDouble(b: Buffer, min: number, max: number): number { @@ -22,23 +22,23 @@ export function parseDouble(b: Buffer, min: number, max: number): number { /** * Converts an ASCII numeric string into an integer. - * + * * Second fastest. */ export function parseDoubleFlat(b: Buffer, min: number, max: number): number { - const sign = -(b[min] === CHAR_MINUS); - b[min + ~sign] = CHAR_ZERO; - return ( - ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) - - sign - ); - } + const sign = -(b[min] === CHAR_MINUS); + b[min + ~sign] = CHAR_ZERO; + return ( + ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) - + sign + ); +} /** * Converts an ASCII numeric string into an integer without branching. * * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}. - * + * * Slowest. */ export function parseDoubleQuan(b: Buffer, min: number, max: number): number { From 44da3a379bd44a83c600153e16629d3eac385382 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Fri, 24 May 2024 22:13:51 -0400 Subject: [PATCH 34/69] Remove 'type' property from message responses as they are unused, Shorten values for a request's 'type' property, Remove type Message and replace with types Request and Response --- src/main/nodejs/havelessbemore/dist/index.cjs | 4 ++-- src/main/nodejs/havelessbemore/dist/index.cjs.map | 2 +- src/main/nodejs/havelessbemore/dist/index.mjs | 4 ++-- src/main/nodejs/havelessbemore/dist/index.mjs.map | 2 +- src/main/nodejs/havelessbemore/src/index.ts | 8 ++++---- src/main/nodejs/havelessbemore/src/main.ts | 4 ++-- src/main/nodejs/havelessbemore/src/types/mergeRequest.ts | 6 +++--- src/main/nodejs/havelessbemore/src/types/mergeResponse.ts | 5 ++--- src/main/nodejs/havelessbemore/src/types/message.ts | 3 --- .../nodejs/havelessbemore/src/types/processRequest.ts | 6 +++--- .../nodejs/havelessbemore/src/types/processResponse.ts | 5 ++--- src/main/nodejs/havelessbemore/src/types/request.ts | 3 +++ src/main/nodejs/havelessbemore/src/types/response.ts | 3 +++ src/main/nodejs/havelessbemore/src/worker.ts | 6 +++--- 14 files changed, 31 insertions(+), 30 deletions(-) delete mode 100644 src/main/nodejs/havelessbemore/src/types/message.ts create mode 100644 src/main/nodejs/havelessbemore/src/types/request.ts create mode 100644 src/main/nodejs/havelessbemore/src/types/response.ts diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs b/src/main/nodejs/havelessbemore/dist/index.cjs index b9565f8..93cc051 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs +++ b/src/main/nodejs/havelessbemore/dist/index.cjs @@ -24,6 +24,6 @@ * SOFTWARE. */ -"use strict";var V=require("node:os"),j=require("node:url"),N=require("node:worker_threads"),L=require("node:fs"),z=require("fs/promises"),J=require("worker_threads"),X=typeof document<"u"?document.currentScript:null;const U=1e4,Q=100,x=107,ee=16384,te=1048576,re=1048576,ne=152e-6,oe=16384,se=1,ae=512,ie=45,P=10,W=59,C=48,q=32,_e=216;function k(e,n,r){return e>n?e<=r?e:r:n}async function ce(e,n,r,l=0){const i=await z.open(e);try{const s=(await i.stat()).size,f=Math.max(l,Math.floor(s/n)),u=Buffer.allocUnsafe(r),o=[];let a=0;for(let c=f;c=0&&_e.length&&(e=Z(e,s+S)),e[p]+=S,e[i]=s,e[s]=e[B]),i=s}return[e,i]}function K(e=0,n=Ee){n=Math.max(b,n);const r=new Int32Array(new SharedArrayBuffer(n<<2));return r[p]=b,r[B]=e,r}function Z(e,n=0){const r=e[p];n=Math.max(n,Math.ceil(r*fe));const l=new Int32Array(new SharedArrayBuffer(n<<2));for(let i=0;ie[o].length&&(e[o]=Z(e[o],t+H),i.add(o)),e[o][p]+=H,e[o][a]=t,e[o][t]=w,e[o][t+O]=R;else{const E=e[o][t];o!==E&&(t=e[o][t+O]),s.push([E,t,w,R])}}a+=D,I+=D}}s.splice(0,f)}while(s.length>0);return Array.from(i)}function pe(e,n,r,l,i="",s){const f=new Array(n.length+1);f[0]=[r,g+y,0];let u=0,o=!1;do{let[a,c,I]=f[u];if(I>=v){--u;continue}f[u][1]+=D,++f[u][2];let _=e[a][c];if(_===h)continue;const T=e[a][_];a!==T&&(_=e[a][_+O],a=T),n[u]=I+q,f[++u]=[a,_+y,0];const R=e[a][_+m];R!==h&&(o&&l.write(i),o=!0,s(l,n,u,R))}while(u>=0)}function ye(e){const n=new J.Worker(e);return n.on("error",r=>{throw r}),n.on("messageerror",r=>{throw r}),n.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${n.threadId} exited with code ${r}`)}),n}function G(e,n){return new Promise(r=>{e.once("message",r),e.postMessage(n)})}async function ge(e,n,r,l=""){r=k(r,se,ae);const i=await ce(e,r,x,oe);r=i.length;const s=new SharedArrayBuffer(U*r+1<<4),f=new Int16Array(s),u=new Int16Array(s,2),o=new Uint32Array(s,4),a=new Float64Array(s,8),c=new Array(r),I=new Array(r);for(let t=0;t{c[E.id]=E.trie});for(let t=_.length-1;t>0;--t){const E=t-1>>1,d=t;_[E]=_[E].then(()=>_[d]).then(()=>G(I[E],{type:"merge_request",a:E,b:d,counts:o,maxes:u,mins:f,sums:a,tries:c})).then(M=>{for(const A of M.ids)c[A]=M.tries[A]})}for(let t=0;tI[t].terminate());await Promise.all(_);const T=L.createWriteStream(l,{fd:l.length<1?1:void 0,flags:"a",highWaterMark:re}),R=Buffer.allocUnsafe(Q);T.write("{"),pe(c,R,0,T,", ",w),T.end(`} -`);function w(t,E,d,M){const A=Math.round(a[M<<1]/o[M<<2]);t.write(E.toString("utf8",0,d)),t.write("="),t.write((f[M<<3]/10).toFixed(1)),t.write("/"),t.write((A/10).toFixed(1)),t.write("/"),t.write((u[M<<3]/10).toFixed(1))}}const Y=11*C,$=111*C;function Ne(e,n,r){return e[n]===ie?(++n,n+4>r?-(10*e[n]+e[n+2]-Y):-(100*e[n]+10*e[n+1]+e[n+3]-$)):n+4>r?10*e[n]+e[n+2]-Y:100*e[n]+10*e[n+1]+e[n+3]-$}async function De({end:e,filePath:n,id:r,start:l,counts:i,maxes:s,mins:f,sums:u}){if(l>=e)return{type:"process_response",id:r,trie:K(r,0)};let o=K(r),a=r*U+1;const c=Buffer.allocUnsafe(x),I=L.createReadStream(n,{start:l,end:e-1,highWaterMark:ue(e-l)});let _=0,T;for await(const t of I){const E=t.length;for(let d=0;d=E?s[t]:E,++i[t>>1],u[t>>2]+=E}return{type:"process_response",id:r,trie:o}}function Oe({a:e,b:n,tries:r,counts:l,maxes:i,mins:s,sums:f}){function u(o,a){o<<=3,a<<=3,s[o]=Math.min(s[o],s[a]),i[o]=Math.max(i[o],i[a]),l[o>>1]+=l[a>>1],f[o>>2]+=f[a>>2]}return{type:"merge_response",ids:me(r,e,n,u),tries:r}}if(N.isMainThread){const e=j.fileURLToPath(typeof document>"u"?require("url").pathToFileURL(__filename).href:X&&X.src||new URL("index.cjs",document.baseURI).href);ge(process.argv[2],e,V.availableParallelism())}else N.parentPort.addListener("message",async e=>{if(e.type==="process_request")N.parentPort.postMessage(await De(e));else if(e.type==="merge_request")N.parentPort.postMessage(Oe(e));else throw new Error("Unknown message type")}); +"use strict";var V=require("node:os"),j=require("node:url"),D=require("node:worker_threads"),L=require("node:fs"),z=require("fs/promises"),J=require("worker_threads"),X=typeof document<"u"?document.currentScript:null;const U=1e4,Q=100,x=107,ee=16384,te=1048576,re=1048576,ne=152e-6,oe=16384,ae=1,se=512,ie=45,P=10,W=59,C=48,k=32,_e=216;function v(e,n,r){return e>n?e<=r?e:r:n}async function ce(e,n,r,l=0){const i=await z.open(e);try{const a=(await i.stat()).size,f=Math.max(l,Math.floor(a/n)),u=Buffer.allocUnsafe(r),o=[];let s=0;for(let c=f;c=0&&_e.length&&(e=Z(e,a+S)),e[g]+=S,e[i]=a,e[a]=e[b]),i=a}return[e,i]}function K(e=0,n=Ee){n=Math.max(q,n);const r=new Int32Array(new SharedArrayBuffer(n<<2));return r[g]=q,r[b]=e,r}function Z(e,n=0){const r=e[g];n=Math.max(n,Math.ceil(r*fe));const l=new Int32Array(new SharedArrayBuffer(n<<2));for(let i=0;ie[o].length&&(e[o]=Z(e[o],t+H),i.add(o)),e[o][g]+=H,e[o][s]=t,e[o][t]=w,e[o][t+O]=R;else{const E=e[o][t];o!==E&&(t=e[o][t+O]),a.push([E,t,w,R])}}s+=p,I+=p}}a.splice(0,f)}while(a.length>0);return Array.from(i)}function ge(e,n,r,l,i="",a){const f=new Array(n.length+1);f[0]=[r,N+y,0];let u=0,o=!1;do{let[s,c,I]=f[u];if(I>=F){--u;continue}f[u][1]+=p,++f[u][2];let _=e[s][c];if(_===h)continue;const T=e[s][_];s!==T&&(_=e[s][_+O],s=T),n[u]=I+k,f[++u]=[s,_+y,0];const R=e[s][_+m];R!==h&&(o&&l.write(i),o=!0,a(l,n,u,R))}while(u>=0)}function ye(e){const n=new J.Worker(e);return n.on("error",r=>{throw r}),n.on("messageerror",r=>{throw r}),n.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${n.threadId} exited with code ${r}`)}),n}function G(e,n){return new Promise(r=>{e.once("message",r),e.postMessage(n)})}async function Ne(e,n,r,l=""){r=v(r,ae,se);const i=await ce(e,r,x,oe);r=i.length;const a=new SharedArrayBuffer(U*r+1<<4),f=new Int16Array(a),u=new Int16Array(a,2),o=new Uint32Array(a,4),s=new Float64Array(a,8),c=new Array(r),I=new Array(r);for(let t=0;t{c[E.id]=E.trie});for(let t=_.length-1;t>0;--t){const E=t-1>>1,d=t;_[E]=_[E].then(()=>_[d]).then(()=>G(I[E],{type:"merge",a:E,b:d,counts:o,maxes:u,mins:f,sums:s,tries:c})).then(M=>{for(const A of M.ids)c[A]=M.tries[A]})}for(let t=0;tI[t].terminate());await Promise.all(_);const T=L.createWriteStream(l,{fd:l.length<1?1:void 0,flags:"a",highWaterMark:re}),R=Buffer.allocUnsafe(Q);T.write("{"),ge(c,R,0,T,", ",w),T.end(`} +`);function w(t,E,d,M){const A=Math.round(s[M<<1]/o[M<<2]);t.write(E.toString("utf8",0,d)),t.write("="),t.write((f[M<<3]/10).toFixed(1)),t.write("/"),t.write((A/10).toFixed(1)),t.write("/"),t.write((u[M<<3]/10).toFixed(1))}}const Y=11*C,$=111*C;function De(e,n,r){return e[n]===ie?(++n,n+4>r?-(10*e[n]+e[n+2]-Y):-(100*e[n]+10*e[n+1]+e[n+3]-$)):n+4>r?10*e[n]+e[n+2]-Y:100*e[n]+10*e[n+1]+e[n+3]-$}async function pe({end:e,filePath:n,id:r,start:l,counts:i,maxes:a,mins:f,sums:u}){if(l>=e)return{id:r,trie:K(r,0)};let o=K(r),s=r*U+1;const c=Buffer.allocUnsafe(x),I=L.createReadStream(n,{start:l,end:e-1,highWaterMark:ue(e-l)});let _=0,T;for await(const t of I){const E=t.length;for(let d=0;d=E?a[t]:E,++i[t>>1],u[t>>2]+=E}return{id:r,trie:o}}function Oe({a:e,b:n,tries:r,counts:l,maxes:i,mins:a,sums:f}){function u(o,s){o<<=3,s<<=3,a[o]=Math.min(a[o],a[s]),i[o]=Math.max(i[o],i[s]),l[o>>1]+=l[s>>1],f[o>>2]+=f[s>>2]}return{ids:me(r,e,n,u),tries:r}}if(D.isMainThread){const e=j.fileURLToPath(typeof document>"u"?require("url").pathToFileURL(__filename).href:X&&X.src||new URL("index.cjs",document.baseURI).href);Ne(process.argv[2],e,V.availableParallelism())}else D.parentPort.addListener("message",async e=>{if(e.type==="process")D.parentPort.postMessage(await pe(e));else if(e.type==="merge")D.parentPort.postMessage(Oe(e));else throw new Error("Unknown message type")}); //# sourceMappingURL=index.cjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs.map b/src/main/nodejs/havelessbemore/dist/index.cjs.map index 582fad0..4ed87f7 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.cjs.map @@ -1 +1 @@ -{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/constants/utf8.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/utils/parse.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n *\n * @remarks\n *\n * Changing this value affects the `count` and\n * `sum` values used for calculating a station's\n * average temperature.\n *\n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n *\n * @remarks\n *\n * Changing this value affects the `min`, `max` and `sum` values\n * used for calculating a station's min, max and avg\n * temperatures, respectively.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n *\n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n *\n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n *\n * @remarks\n *\n * This limit should be sufficient for most use cases.\n * However, feel free to adjust up or down as needed.\n *\n * There is not much basis for the current value.\n * Development was done with at most 8 workers and\n * a reasonable input file, with memory never exceeding\n * 20 MiB total across all workers.\n *\n * In theory, the challenge constraints allow for input\n * files that would require each worker using upwards of\n * 800 MiB; 10K stations with completely unique 100 byte names,\n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = trie[index /*+ TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index /*+ TRIE_PTR_IDX_IDX*/] = child;\n // Initialize node\n trie[child /* + TRIE_NODE_ID_IDX*/] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr /* + TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child /* + TRIE_NODE_ID_IDX*/];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi /* + TRIE_PTR_IDX_IDX*/];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri /*+ TRIE_NODE_ID_IDX*/];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai /*+ TRIE_PTR_IDX_IDX*/];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai /*+ TRIE_PTR_IDX_IDX*/] = li;\n // Initialize redirect\n tries[at][li /* + TRIE_XPTR_ID_IDX*/] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li /* + TRIE_NODE_ID_IDX*/];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr /* + TRIE_PTR_IDX_IDX*/];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI /* + TRIE_NODE_ID_IDX*/];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { CHAR_MINUS, CHAR_ZERO } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CHAR_MINUS);\n b[min + ~sign] = CHAR_ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CHAR_MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { parseDouble } from \"./utils/parse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CHAR_NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 4;\n if (buffer[semI - 2] === CHAR_SEMICOLON) {\n semI -= 2;\n } else if (buffer[semI - 1] === CHAR_SEMICOLON) {\n semI -= 1;\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { type: \"merge_response\", ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge_request\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","MIN_WORKERS","MAX_WORKERS","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","CHAR_ZERO_11","CHAR_ZERO_111","parseDouble","stations","createReadStream","bufI","leaf","chunk","N","semI","tempV","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","_documentCurrentScript","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/constants/utf8.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/utils/parse.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n *\n * @remarks\n *\n * Changing this value affects the `count` and\n * `sum` values used for calculating a station's\n * average temperature.\n *\n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n *\n * @remarks\n *\n * Changing this value affects the `min`, `max` and `sum` values\n * used for calculating a station's min, max and avg\n * temperatures, respectively.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n *\n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n *\n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n *\n * @remarks\n *\n * This limit should be sufficient for most use cases.\n * However, feel free to adjust up or down as needed.\n *\n * There is not much basis for the current value.\n * Development was done with at most 8 workers and\n * a reasonable input file, with memory never exceeding\n * 20 MiB total across all workers.\n *\n * In theory, the challenge constraints allow for input\n * files that would require each worker using upwards of\n * 800 MiB; 10K stations with completely unique 100 byte names,\n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = trie[index /*+ TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index /*+ TRIE_PTR_IDX_IDX*/] = child;\n // Initialize node\n trie[child /* + TRIE_NODE_ID_IDX*/] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr /* + TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child /* + TRIE_NODE_ID_IDX*/];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi /* + TRIE_PTR_IDX_IDX*/];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri /*+ TRIE_NODE_ID_IDX*/];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai /*+ TRIE_PTR_IDX_IDX*/];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai /*+ TRIE_PTR_IDX_IDX*/] = li;\n // Initialize redirect\n tries[at][li /* + TRIE_XPTR_ID_IDX*/] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li /* + TRIE_NODE_ID_IDX*/];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr /* + TRIE_PTR_IDX_IDX*/];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI /* + TRIE_NODE_ID_IDX*/];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { CHAR_MINUS, CHAR_ZERO } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CHAR_MINUS);\n b[min + ~sign] = CHAR_ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CHAR_MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { parseDouble } from \"./utils/parse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CHAR_NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 4;\n if (buffer[semI - 2] === CHAR_SEMICOLON) {\n semI -= 2;\n } else if (buffer[semI - 1] === CHAR_SEMICOLON) {\n semI -= 1;\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Request } from \"./types/request\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === \"process\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","MIN_WORKERS","MAX_WORKERS","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","CHAR_ZERO_11","CHAR_ZERO_111","parseDouble","stations","createReadStream","bufI","leaf","chunk","N","semI","tempV","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","_documentCurrentScript","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index 62a3e53..a656b42 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -24,6 +24,6 @@ * SOFTWARE. */ -import{availableParallelism as Y}from"node:os";import{fileURLToPath as $}from"node:url";import{isMainThread as V,parentPort as H}from"node:worker_threads";import{createWriteStream as z,createReadStream as j}from"node:fs";import{open as J}from"fs/promises";import{Worker as Q}from"worker_threads";const X=1e4,tt=100,L=107,et=16384,rt=1048576,nt=1048576,ot=152e-6,st=16384,at=1,it=512,_t=45,x=10,U=59,W=48,P=32,ct=216;function C(t,n,r){return t>n?t<=r?t:r:n}async function Et(t,n,r,I=0){const i=await J(t);try{const s=(await i.stat()).size,l=Math.max(I,Math.floor(s/n)),E=Buffer.allocUnsafe(r),o=[];let a=0;for(let c=l;c=0&&_t.length&&(t=b(t,s+O)),t[p]+=O,t[i]=s,t[s]=t[B]),i=s}return[t,i]}function Z(t=0,n=lt){n=Math.max(K,n);const r=new Int32Array(new SharedArrayBuffer(n<<2));return r[p]=K,r[B]=t,r}function b(t,n=0){const r=t[p];n=Math.max(n,Math.ceil(r*It));const I=new Int32Array(new SharedArrayBuffer(n<<2));for(let i=0;it[o].length&&(t[o]=b(t[o],e+S),i.add(o)),t[o][p]+=S,t[o][a]=e,t[o][e]=w,t[o][e+D]=R;else{const f=t[o][e];o!==f&&(e=t[o][e+D]),s.push([f,e,w,R])}}a+=N,u+=N}}s.splice(0,l)}while(s.length>0);return Array.from(i)}function gt(t,n,r,I,i="",s){const l=new Array(n.length+1);l[0]=[r,y+g,0];let E=0,o=!1;do{let[a,c,u]=l[E];if(u>=F){--E;continue}l[E][1]+=N,++l[E][2];let _=t[a][c];if(_===m)continue;const T=t[a][_];a!==T&&(_=t[a][_+D],a=T),n[E]=u+P,l[++E]=[a,_+g,0];const R=t[a][_+d];R!==m&&(o&&I.write(i),o=!0,s(I,n,E,R))}while(E>=0)}function yt(t){const n=new Q(t);return n.on("error",r=>{throw r}),n.on("messageerror",r=>{throw r}),n.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${n.threadId} exited with code ${r}`)}),n}function G(t,n){return new Promise(r=>{t.once("message",r),t.postMessage(n)})}async function Nt(t,n,r,I=""){r=C(r,at,it);const i=await Et(t,r,L,st);r=i.length;const s=new SharedArrayBuffer(X*r+1<<4),l=new Int16Array(s),E=new Int16Array(s,2),o=new Uint32Array(s,4),a=new Float64Array(s,8),c=new Array(r),u=new Array(r);for(let e=0;e{c[f.id]=f.trie});for(let e=_.length-1;e>0;--e){const f=e-1>>1,h=e;_[f]=_[f].then(()=>_[h]).then(()=>G(u[f],{type:"merge_request",a:f,b:h,counts:o,maxes:E,mins:l,sums:a,tries:c})).then(M=>{for(const A of M.ids)c[A]=M.tries[A]})}for(let e=0;eu[e].terminate());await Promise.all(_);const T=z(I,{fd:I.length<1?1:void 0,flags:"a",highWaterMark:nt}),R=Buffer.allocUnsafe(tt);T.write("{"),gt(c,R,0,T,", ",w),T.end(`} -`);function w(e,f,h,M){const A=Math.round(a[M<<1]/o[M<<2]);e.write(f.toString("utf8",0,h)),e.write("="),e.write((l[M<<3]/10).toFixed(1)),e.write("/"),e.write((A/10).toFixed(1)),e.write("/"),e.write((E[M<<3]/10).toFixed(1))}}const q=11*W,v=111*W;function Dt(t,n,r){return t[n]===_t?(++n,n+4>r?-(10*t[n]+t[n+2]-q):-(100*t[n]+10*t[n+1]+t[n+3]-v)):n+4>r?10*t[n]+t[n+2]-q:100*t[n]+10*t[n+1]+t[n+3]-v}async function Ot({end:t,filePath:n,id:r,start:I,counts:i,maxes:s,mins:l,sums:E}){if(I>=t)return{type:"process_response",id:r,trie:Z(r,0)};let o=Z(r),a=r*X+1;const c=Buffer.allocUnsafe(L),u=j(n,{start:I,end:t-1,highWaterMark:ft(t-I)});let _=0,T;for await(const e of u){const f=e.length;for(let h=0;h=f?s[e]:f,++i[e>>1],E[e>>2]+=f}return{type:"process_response",id:r,trie:o}}function Ht({a:t,b:n,tries:r,counts:I,maxes:i,mins:s,sums:l}){function E(o,a){o<<=3,a<<=3,s[o]=Math.min(s[o],s[a]),i[o]=Math.max(i[o],i[a]),I[o>>1]+=I[a>>1],l[o>>2]+=l[a>>2]}return{type:"merge_response",ids:pt(r,t,n,E),tries:r}}if(V){const t=$(import.meta.url);Nt(process.argv[2],t,Y())}else H.addListener("message",async t=>{if(t.type==="process_request")H.postMessage(await Ot(t));else if(t.type==="merge_request")H.postMessage(Ht(t));else throw new Error("Unknown message type")}); +import{availableParallelism as $}from"node:os";import{fileURLToPath as V}from"node:url";import{isMainThread as z,parentPort as H}from"node:worker_threads";import{createWriteStream as j,createReadStream as q}from"node:fs";import{open as J}from"fs/promises";import{Worker as Q}from"worker_threads";const X=1e4,tt=100,L=107,et=16384,rt=1048576,nt=1048576,ot=152e-6,at=16384,st=1,it=512,_t=45,x=10,U=59,W=48,P=32,ct=216;function C(t,n,r){return t>n?t<=r?t:r:n}async function Et(t,n,r,I=0){const i=await J(t);try{const a=(await i.stat()).size,l=Math.max(I,Math.floor(a/n)),E=Buffer.allocUnsafe(r),o=[];let s=0;for(let c=l;c=0&&_t.length&&(t=b(t,a+p)),t[g]+=p,t[i]=a,t[a]=t[B]),i=a}return[t,i]}function Z(t=0,n=lt){n=Math.max(K,n);const r=new Int32Array(new SharedArrayBuffer(n<<2));return r[g]=K,r[B]=t,r}function b(t,n=0){const r=t[g];n=Math.max(n,Math.ceil(r*It));const I=new Int32Array(new SharedArrayBuffer(n<<2));for(let i=0;it[o].length&&(t[o]=b(t[o],e+S),i.add(o)),t[o][g]+=S,t[o][s]=e,t[o][e]=w,t[o][e+O]=R;else{const f=t[o][e];o!==f&&(e=t[o][e+O]),a.push([f,e,w,R])}}s+=D,u+=D}}a.splice(0,l)}while(a.length>0);return Array.from(i)}function Nt(t,n,r,I,i="",a){const l=new Array(n.length+1);l[0]=[r,y+N,0];let E=0,o=!1;do{let[s,c,u]=l[E];if(u>=F){--E;continue}l[E][1]+=D,++l[E][2];let _=t[s][c];if(_===m)continue;const T=t[s][_];s!==T&&(_=t[s][_+O],s=T),n[E]=u+P,l[++E]=[s,_+N,0];const R=t[s][_+d];R!==m&&(o&&I.write(i),o=!0,a(I,n,E,R))}while(E>=0)}function yt(t){const n=new Q(t);return n.on("error",r=>{throw r}),n.on("messageerror",r=>{throw r}),n.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${n.threadId} exited with code ${r}`)}),n}function G(t,n){return new Promise(r=>{t.once("message",r),t.postMessage(n)})}async function Dt(t,n,r,I=""){r=C(r,st,it);const i=await Et(t,r,L,at);r=i.length;const a=new SharedArrayBuffer(X*r+1<<4),l=new Int16Array(a),E=new Int16Array(a,2),o=new Uint32Array(a,4),s=new Float64Array(a,8),c=new Array(r),u=new Array(r);for(let e=0;e{c[f.id]=f.trie});for(let e=_.length-1;e>0;--e){const f=e-1>>1,h=e;_[f]=_[f].then(()=>_[h]).then(()=>G(u[f],{type:"merge",a:f,b:h,counts:o,maxes:E,mins:l,sums:s,tries:c})).then(M=>{for(const A of M.ids)c[A]=M.tries[A]})}for(let e=0;eu[e].terminate());await Promise.all(_);const T=j(I,{fd:I.length<1?1:void 0,flags:"a",highWaterMark:nt}),R=Buffer.allocUnsafe(tt);T.write("{"),Nt(c,R,0,T,", ",w),T.end(`} +`);function w(e,f,h,M){const A=Math.round(s[M<<1]/o[M<<2]);e.write(f.toString("utf8",0,h)),e.write("="),e.write((l[M<<3]/10).toFixed(1)),e.write("/"),e.write((A/10).toFixed(1)),e.write("/"),e.write((E[M<<3]/10).toFixed(1))}}const v=11*W,Y=111*W;function Ot(t,n,r){return t[n]===_t?(++n,n+4>r?-(10*t[n]+t[n+2]-v):-(100*t[n]+10*t[n+1]+t[n+3]-Y)):n+4>r?10*t[n]+t[n+2]-v:100*t[n]+10*t[n+1]+t[n+3]-Y}async function pt({end:t,filePath:n,id:r,start:I,counts:i,maxes:a,mins:l,sums:E}){if(I>=t)return{id:r,trie:Z(r,0)};let o=Z(r),s=r*X+1;const c=Buffer.allocUnsafe(L),u=q(n,{start:I,end:t-1,highWaterMark:ft(t-I)});let _=0,T;for await(const e of u){const f=e.length;for(let h=0;h=f?a[e]:f,++i[e>>1],E[e>>2]+=f}return{id:r,trie:o}}function Ht({a:t,b:n,tries:r,counts:I,maxes:i,mins:a,sums:l}){function E(o,s){o<<=3,s<<=3,a[o]=Math.min(a[o],a[s]),i[o]=Math.max(i[o],i[s]),I[o>>1]+=I[s>>1],l[o>>2]+=l[s>>2]}return{ids:gt(r,t,n,E),tries:r}}if(z){const t=V(import.meta.url);Dt(process.argv[2],t,$())}else H.addListener("message",async t=>{if(t.type==="process")H.postMessage(await pt(t));else if(t.type==="merge")H.postMessage(Ht(t));else throw new Error("Unknown message type")}); //# sourceMappingURL=index.mjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index d479724..61a70c1 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1 +1 @@ -{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/constants/utf8.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/utils/parse.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n *\n * @remarks\n *\n * Changing this value affects the `count` and\n * `sum` values used for calculating a station's\n * average temperature.\n *\n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n *\n * @remarks\n *\n * Changing this value affects the `min`, `max` and `sum` values\n * used for calculating a station's min, max and avg\n * temperatures, respectively.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n *\n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n *\n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n *\n * @remarks\n *\n * This limit should be sufficient for most use cases.\n * However, feel free to adjust up or down as needed.\n *\n * There is not much basis for the current value.\n * Development was done with at most 8 workers and\n * a reasonable input file, with memory never exceeding\n * 20 MiB total across all workers.\n *\n * In theory, the challenge constraints allow for input\n * files that would require each worker using upwards of\n * 800 MiB; 10K stations with completely unique 100 byte names,\n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = trie[index /*+ TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index /*+ TRIE_PTR_IDX_IDX*/] = child;\n // Initialize node\n trie[child /* + TRIE_NODE_ID_IDX*/] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr /* + TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child /* + TRIE_NODE_ID_IDX*/];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi /* + TRIE_PTR_IDX_IDX*/];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri /*+ TRIE_NODE_ID_IDX*/];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai /*+ TRIE_PTR_IDX_IDX*/];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai /*+ TRIE_PTR_IDX_IDX*/] = li;\n // Initialize redirect\n tries[at][li /* + TRIE_XPTR_ID_IDX*/] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li /* + TRIE_NODE_ID_IDX*/];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr /* + TRIE_PTR_IDX_IDX*/];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI /* + TRIE_NODE_ID_IDX*/];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process_request\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge_request\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { CHAR_MINUS, CHAR_ZERO } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CHAR_MINUS);\n b[min + ~sign] = CHAR_ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CHAR_MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { parseDouble } from \"./utils/parse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { type: \"process_response\", id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CHAR_NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 4;\n if (buffer[semI - 2] === CHAR_SEMICOLON) {\n semI -= 2;\n } else if (buffer[semI - 1] === CHAR_SEMICOLON) {\n semI -= 1;\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { type: \"process_response\", id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { type: \"merge_response\", ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Message } from \"./types/message\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Message) => {\n if (msg.type === \"process_request\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge_request\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","MIN_WORKERS","MAX_WORKERS","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","CHAR_ZERO_11","CHAR_ZERO_111","parseDouble","stations","createReadStream","bufI","leaf","chunk","N","semI","tempV","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;wSAaa,CAaAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAe,IAafC,CAAuB,CAAA,CAAA,CAAA,CAAA,CAAA,CA6BvBC,CAAgB,CAAA,CAAA,CAAA,CAAA,CCjEhBC,CAAsB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAKtBC,CAAsB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAKtBC,CAAsB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAMtBC,CAAwB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAKxBC,CAAiB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CCrBjBC,CAAc,CAAA,CAAA,CAAA,CAwBdC,GAAc,CCtBdC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAa,CAKbC,CAAAA,CAAAA,CAAAA,CAAe,CAUfC,CAAAA,CAAAA,CAAAA,CAAiB,CAKjBC,CAAAA,CAAAA,CAAAA,CAAY,GAWZC,CAAgB,CAAA,CAAA,CAAA,CAYhBC,CAAiB,CAAA,CAAA,CAAA,CAAA,CAAA,EC9BdC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAMC,CAAeC,CAAAA,CAAAA,CAAaC,EAAqB,CACrE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAOF,CAAQC,CAAAA,CAAAA,CAAOD,CAASE,CAAAA,CAAAA,CAAAA,CAAMF,CAAQE,CAAAA,CAAAA,CAAOD,CACtD,EAoBsBE,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACpBC,CACAC,CAAAA,CAAAA,CACAC,CACAC,CAAAA,CAAAA,CAAU,EACmB,CAE7B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMC,CAAKL,CAAAA,CAAQ,CAChC,CAAA,CAAA,CAAA,CAAI,CAEF,CAAMM,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAQ,CAAMF,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAK,QAAQ,CAE3BG,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAY,KAAK,CAAIJ,CAAAA,CAAAA,CAAAA,CAAAA,CAAS,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMG,CAAOL,CAAAA,CAAM,CAAC,CAAA,CAEvDO,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAYN,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAa,CACzCO,CAAAA,CAAAA,CAA6B,GAEnC,IAAIC,CAAQ,CAAA,CAAA,CACZ,CAASC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAMJ,CAAWI,CAAAA,CAAAA,CAAML,CAAMK,CAAAA,CAAAA,CAAAA,CAAOJ,EAAW,CAEtD,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMK,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMR,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAKI,CAAQ,CAAA,CAAA,CAAGN,EAAeS,CAAG,CAAA,CAEnDE,CAAUL,CAAAA,CAAAA,CAAO,CAAQlB,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAY,CAEvCuB,CAAAA,CAAAA,CAAAA,CAAW,CAAKA,CAAAA,CAAAA,CAAAA,CAAUD,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAEhCD,CAAOE,CAAAA,CAAAA,CAAAA,CAAU,CAEjBJ,CAAAA,CAAAA,CAAO,KAAK,CAACC,CAAAA,CAAOC,CAAG,CAAC,CAExBD,CAAAA,CAAAA,CAAQC,CAEZ,CAAA,CAEA,CAAID,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAQJ,CACVG,CAAAA,CAAAA,CAAAA,CAAO,CAAK,CAAA,CAAA,CAAA,CAAA,CAACC,CAAOJ,CAAAA,CAAI,CAAC,CAGpBG,CAAAA,CACT,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAEA,CAAML,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAK,OACb,CACF,CASO,CAASU,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAiBR,CAAsB,CAAA,CAErD,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAQrB,GAERqB,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAKA,CAAAA,CAAAA,CAAAA,CAAAA,CAAI,CAAC,CAAA,CAEjCA,EAAO,CAAKA,CAAAA,CAAAA,CAAAA,CAELX,CAAMW,CAAAA,CAAAA,CAAMxB,CAAqBC,CAAAA,CAAAA,CAAAA,CAAmB,CAC7D,CC3Fa,MAAAgC,CAAoB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAKpBC,CAAqB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAWrBC,CAAmB,CAAA,CAAA,CAAA,CAEnBC,CAAeD,CAAAA,CAAAA,CAAAA,CAQfE,CAAmB,CAAA,CAAA,CAAA,CAGnBC,CAAoB,CAAA,CAAA,CACpBC,CAAoB,CAAA,CAAA,CAAA,CAEpBC,CAAgBH,CAAAA,CAAAA,CAAAA,CAAmBE,GAKnCE,CAAmB,CAAA,CAAA,CAAA,CACnBC,CAAmB,CAAA,CAAA,CAAA,CAGnBC,CAAsB,CAAA,CAAA,CACtBC,CAAsB,CAAA,CAAA,CAAA,CAGtBC,EAAyB,CACzBC,CAAAA,CAAAA,CAAyBlC,CACzBmC,CAAAA,CAAAA,CAAAA,CAAyBX,CAAeU,CAAAA,CAAAA,CAExCE,CACXN,CAAAA,CAAAA,CAAAA,CAAmBE,GAAsBG,CAO9BE,CAAAA,CAAAA,CAAY,CAGZC,CAAAA,CAAAA,CAAgB,CAChBC,CAAAA,CAAAA,CAAAA,CAAgB,CAGhBC,CAAAA,CAAAA,CAAgB,CAChBC,CAAAA,CAAAA,CAAAA,CAAgBL,CAGhBM,CAAAA,CAAAA,CAAcF,CAAgBX,CAAAA,CAAAA,CAAAA,CAE9Bc,CAAWJ,CAAAA,CAAAA,CAAAA,CAAgBE,GC3DxB,CAAAG,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACdC,CACAC,CAAAA,CAAAA,CACA3C,CACAC,CAAAA,CAAAA,CACsB,CACtB,CAAA,CAAA,CAAA,CAAI2C,EAAQP,CACZ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAOrC,CAAMC,CAAAA,CAAAA,CAAAA,CAAK,CAChB2C,CAAAA,CAAAA,CACEd,CAA8Ca,CAAAA,CAAAA,CAAAA,CAAI3C,GAAK,CAAIJ,CAAAA,CAAAA,CAAAA,CAC7D,CAAIiD,CAAAA,CAAAA,CAAAA,CAAAA,CAAQH,CAAKE,CAAAA,CAA4B,CACzCC,CAAAA,CAAAA,CAAAA,CAAAA,CAAUX,CAEZW,CAAAA,CAAAA,CAAAA,CAAAA,CAAQH,CAAKP,CAAAA,CAAa,CACtBU,CAAAA,CAAAA,CAAQZ,CAAgBS,CAAAA,CAAAA,CAAK,SAC/BA,CAAOI,CAAAA,CAAAA,CAAKJ,CAAMG,CAAAA,CAAAA,CAAQZ,CAAa,CAAA,CAAA,CAEzCS,CAAKP,CAAAA,CAAa,CAAKF,CAAAA,CAAAA,CAAAA,CAEvBS,CAAKE,CAAAA,CAA4B,CAAIC,CAAAA,CAAAA,CAErCH,CAAKG,CAAAA,CAA6B,EAAIH,CAAKH,CAAAA,CAAW,CAExDK,CAAAA,CAAAA,CAAAA,CAAQC,CACV,CAEA,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAACH,CAAME,CAAAA,CAAK,CACrB,CA8BgB,CAAAG,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAWC,CAAK,CAAA,CAAA,CAAGvC,EAAOS,CAA+B,CAAA,CAAA,CACvET,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAI+B,CAAAA,CAAAA,CAAAA,CAAAA,CAAU/B,CAAI,CAAA,CAC9B,MAAMiC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAI,CAAW,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAkBjC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAQ,CAAC,CAAC,EAC5D,CAAAiC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAKP,CAAa,CAAA,CAAIK,CACtBE,CAAAA,CAAAA,CAAKH,CAAW,CAAA,CAAIS,CACbN,CAAAA,CACT,UAEgBI,CAAKJ,CAAAA,CAAAA,CAAkBpC,CAAU,CAAA,CAAA,CAAe,CAC9D,CAAM2C,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAASP,CAAKP,CAAAA,CAAa,CACjC7B,CAAAA,CAAAA,CAAU,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAIA,EAAS,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK2C,CAAS9B,CAAAA,CAAAA,CAAkB,CAAC,CAAA,CAClE,CAAM+B,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAO,IAAI,CAAW,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAkB5C,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAW,CAAC,CAAC,CAC/D,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS6C,CAAI,CAAA,CAAA,CAAGA,CAAIF,CAAAA,CAAAA,CAAQ,CAAEE,CAAAA,CAAAA,CAC5BD,CAAKC,CAAAA,CAAC,EAAIT,CAAKS,CAAAA,CAAC,CAElB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAOD,CACT,EAEgBE,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACdC,EACAC,CACAC,CAAAA,CAAAA,CACAC,CACU,CAAA,CACV,CAAMC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAQ,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACZC,EAA4C,CAChD,CAACJ,CAAIjB,CAAAA,CAAAA,CAAekB,CAAIlB,CAAAA,CAAa,CACvC,CAAA,CAEA,CAAG,CAAA,CACD,CAAMsB,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAID,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAChB,CAASE,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAI,EAAGA,CAAID,CAAAA,CAAAA,CAAG,CAAEC,CAAAA,CAAAA,CAAG,CAE1B,CAAA,CAAA,CAAI,CAACN,CAAAA,CAAIO,EAAIN,CAAIO,CAAAA,CAAE,CAAIJ,CAAAA,CAAAA,CAAME,CAAC,CAAA,CAG9B,CAAMG,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAMV,EAAME,CAAE,CAAA,CAAEO,CAAKlC,CAAAA,CAAmB,CAC9C,CAAA,CAAA,CAAA,CAAImC,CAAQ7B,CAAAA,CAAAA,CAAAA,CAAAA,CAAW,CAErB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM8B,CAAMX,CAAAA,CAAAA,CAAMC,CAAE,CAAA,CAAEO,CAAKjC,CAAAA,CAAmB,EAC1CoC,CAAQ9B,CAAAA,CAAAA,CAAAA,CAAAA,CACVsB,CAAQQ,CAAAA,CAAAA,CAAKD,CAAG,CAAA,CAEhBV,CAAMC,CAAAA,CAAE,EAAEO,CAAKjC,CAAAA,CAAmB,CAAImC,CAAAA,CAE1C,CAGAF,CAAAA,CAAAA,CAAM/B,CACNgC,CAAAA,CAAAA,CAAAA,CAAMhC,EAGN,CAAMmC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAKH,CAAK9B,CAAAA,CAAAA,CAChB,CAAO8B,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAKG,CAAI,CAAA,CAAA,CAEd,CAAIC,CAAAA,CAAAA,CAAAA,CAAAA,CAAKb,CAAME,CAAAA,CAAE,CAAEO,CAAAA,CAA0B,CAC7C,CAAA,CAAA,CAAA,CAAII,IAAOhC,CAAW,CAAA,CAEpB,CAAMiC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAKd,CAAME,CAAAA,CAAE,CAAEW,CAAAA,CAAyB,EAC1CX,CAAOY,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACTD,CAAKb,CAAAA,CAAAA,CAAME,CAAE,CAAA,CAAEW,CAAK3C,CAAAA,CAAiB,GAIvC,CAAI6C,CAAAA,CAAAA,CAAAA,CAAAA,CAAKf,CAAMC,CAAAA,CAAE,CAAEO,CAAAA,CAAyB,CAC5C,CAAA,CAAA,CAAA,CAAIO,CAAOlC,CAAAA,CAAAA,CAAAA,CAAAA,CAETkC,CAAKf,CAAAA,CAAAA,CAAMC,CAAE,CAAA,CAAEnB,CAAa,CAAA,CACxBiC,EAAK3C,CAAgB4B,CAAAA,CAAAA,CAAMC,CAAE,CAAA,CAAE,CACjCD,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAMC,CAAE,CAAA,CAAIR,EAAKO,CAAMC,CAAAA,CAAE,CAAGc,CAAAA,CAAAA,CAAK3C,CAAa,CAAA,CAC9CgC,CAAM,CAAA,CAAA,CAAA,CAAA,CAAIH,CAAE,CAEdD,CAAAA,CAAAA,CAAAA,CAAMC,CAAE,CAAA,CAAEnB,CAAa,CAAA,CAAA,CAAKV,CAE5B4B,CAAAA,CAAAA,CAAMC,CAAE,CAAA,CAAEO,CAAyB,CAAA,CAAIO,CAEvCf,CAAAA,CAAAA,CAAMC,CAAE,CAAA,CAAEc,CAA0B,CAAID,CAAAA,CAAAA,CACxCd,CAAMC,CAAAA,CAAE,CAAEc,CAAAA,CAAAA,CAAK7C,CAAiB,CAAA,CAAI2C,CAC/B,CAAA,CAAA,CAAA,CAAA,CAAA,CAEL,CAAMG,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAKhB,CAAMC,CAAAA,CAAE,CAAEc,CAAAA,CAA0B,EAC3Cd,CAAOe,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACTD,CAAKf,CAAAA,CAAAA,CAAMC,CAAE,CAAA,CAAEc,CAAK7C,CAAAA,CAAiB,CAGvCmC,CAAAA,CAAAA,CAAAA,CAAM,CAAK,CAAA,CAAA,CAAA,CAAA,CAACW,CAAID,CAAAA,CAAAA,CAAID,CAAID,CAAAA,CAAE,CAAC,CAC7B,CACF,CAGAL,CAAAA,CAAAA,CAAMxC,CACNyC,CAAAA,CAAAA,CAAAA,CAAMzC,CACR,CACF,CACAqC,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAGC,CAAAA,CAAC,CACnB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAASD,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,GACxB,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAKD,CAAAA,CAAAA,CAAAA,CAAAA,CAAK,CACzB,CAEO,CAASa,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACdjB,CACAV,CAAAA,CAAAA,CACA4B,CACAC,CAAAA,CAAAA,CACAC,CAAY,CAAA,CAAA,CAAA,CACZC,CAMM,CAAA,CACN,MAAMC,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAI,CAAgChC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAI,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAChEgC,CAAAA,CAAAA,CAAM,CAAC,CAAI,CAAA,CAACJ,CAAWlC,CAAAA,CAAAA,CAAgBP,CAAwB,CAAA,CAAC,CAEhE,CAAA,CAAA,CAAA,CAAA,CAAI8C,EAAM,CACNC,CAAAA,CAAAA,CAAO,CACX,CAAA,CAAA,CAAA,CAAG,CAED,CAAA,CAAA,CAAI,CAACC,CAAAA,CAAOC,CAAUC,CAAAA,CAAQ,CAAIL,CAAAA,CAAAA,CAAMC,CAAG,CAAA,CAG3C,CAAII,CAAAA,CAAAA,CAAAA,CAAAA,CAAYjD,EAAwB,CACtC,CAAA,CAAE6C,CACF,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACF,CAGAD,CAAAA,CAAMC,CAAG,CAAA,CAAE,CAAC,CAAKvD,CAAAA,CAAAA,CAAAA,CACjB,CAAEsD,CAAAA,CAAAA,CAAMC,CAAG,CAAA,CAAE,CAAC,CAAA,CAGd,IAAIK,CAAS5B,CAAAA,CAAAA,CAAMyB,CAAK,CAAA,CAAEC,CAAgC,CAAA,CAC1D,CAAIE,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAW/C,CACb,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAIF,CAAMgD,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAa7B,CAAMyB,CAAAA,CAAK,CAAEG,CAAAA,CAA8B,EAC1DH,CAAUI,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACZD,CAAS5B,CAAAA,CAAAA,CAAMyB,CAAK,CAAA,CAAEG,CAAS1D,CAAAA,CAAiB,EAChDuD,CAAQI,CAAAA,CAAAA,CAAAA,CAIVvC,CAAIiC,CAAAA,CAAG,CAAII,CAAAA,CAAAA,CAAWpF,CACtB+E,CAAAA,CAAAA,CAAM,EAAEC,CAAG,CAAA,CAAI,CAACE,CAAAA,CAAOG,CAASnD,CAAAA,CAAAA,CAAwB,CAAC,CAAA,CAGzD,CAAMqD,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAa9B,CAAMyB,CAAAA,CAAK,CAAEG,CAAAA,CAAAA,CAASrD,CAAmB,CAAA,CACxDuD,IAAejD,CAEb2C,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACFL,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMC,CAAS,CAAA,CAExBI,CAAO,CAAA,CAAA,CAAA,CACPH,EAAWF,CAAQ7B,CAAAA,CAAAA,CAAKiC,CAAKO,CAAAA,CAAU,CAE3C,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAASP,CAAO,CAAA,CAAA,CAAA,CAClB,CCpOgB,CAAAQ,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAaC,CAA4B,CAAA,CACvD,CAAMC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAS,CAAIC,CAAAA,CAAAA,CAAAA,CAAAA,CAAOF,CAAU,CAAA,CACpC,CAAAC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAO,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAUE,CAAQ,CAAA,CAAA,CAC1B,MAAMA,CACR,CAAC,CACDF,CAAAA,CAAAA,CAAO,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAiBE,CAAQ,CAAA,CAAA,CACjC,MAAMA,CACR,CAAC,CACDF,CAAAA,CAAAA,CAAO,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAASG,CAAS,CAAA,CAAA,CAC1B,GAAIA,CAAO,CAAA,CAAA,CAAA,CAAKA,CAAO,CAAA,CAAA,CACrB,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAUH,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAqBG,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAI,CAAE,CAAA,CAExE,CAAC,CAAA,CACMH,CACT,CAUgB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAI,CAAeJ,CAAAA,CAAAA,CAAgBK,CAAwB,CAAA,CACrE,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,QAAcC,CAAY,CAAA,CAAA,CACnCN,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAWM,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAO,CAC9BN,CAAAA,CAAAA,CAAO,YAAYK,CAAG,CACxB,CAAC,CACH,gBCnBsBE,CACpB1F,CAAAA,CAAAA,CAAAA,CACAkF,CACAS,CAAAA,CAAAA,CACAC,CAAU,CAAA,CAAA,CAAA,CACK,CAEfD,CAAAA,CAAahG,CAAMgG,CAAAA,CAAAA,CAAYxG,GAAaC,CAAW,CAAA,CAAA,CAGvD,CAAMqB,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAS,CAAMV,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACnBC,CACA2F,CAAAA,CAAAA,CACA9G,CACAK,CAAAA,CAAAA,CACF,CAGAyG,CAAAA,CAAAA,CAAalF,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAGpB,CAAMoF,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAS,IAAI,CAAmBlH,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAegH,CAAa,CAAA,CAAA,CAAA,CAAM,CAAC,CAAA,CACnEG,CAAO,CAAA,CAAA,CAAA,CAAA,CAAI,CAAWD,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAM,CAC5BE,CAAAA,CAAAA,CAAQ,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAWF,CAAQ,CAAA,CAAC,EAChCG,CAAS,CAAA,CAAA,CAAA,CAAA,CAAI,CAAYH,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAQ,CAAC,CAAA,CAClCI,CAAO,CAAA,CAAA,CAAA,CAAA,CAAI,aAAaJ,CAAQ,CAAA,CAAC,CACjC3C,CAAAA,CAAAA,CAAQ,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAkByC,CAAU,CAAA,CAGxCO,EAAU,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAcP,CAAU,CAAA,CAC5C,CAAS3C,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAI,CAAGA,CAAAA,CAAAA,CAAI2C,CAAY,CAAA,CAAA,CAAE3C,CAChCkD,CAAAA,CAAAA,CAAQlD,CAAC,CAAA,CAAIiC,CAAaC,CAAAA,CAAAA,CAAU,EAItC,CAAMiB,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAQ,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAwBR,CAAU,CAAA,CACpD,CAAS3C,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAI,EAAGA,CAAI2C,CAAAA,CAAAA,CAAY,CAAE3C,CAAAA,CAAAA,CAChCmD,CAAMnD,CAAAA,CAAC,CAAIuC,CAAAA,CAAAA,CAAsCW,EAAQlD,CAAC,CAAA,CAAG,CAC3D,CAAA,CAAA,CAAA,CAAA,CAAM,CACN,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAgD,CACA,CAAA,CAAA,CAAA,CAAA,CAAKvF,CAAOuC,CAAAA,CAAC,CAAE,CAAA,CAAC,CAChB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAhD,CACA,CAAA,CAAA,CAAA,CAAIgD,EACJ,CAAA+C,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACA,CAAAD,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACA,CAAOrF,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAOuC,CAAC,CAAA,CAAE,CAAC,CAClB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAiD,CACF,CAAC,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMrF,CAAQ,CAAA,CAAA,CACfsC,EAAMtC,CAAI,CAAA,CAAA,CAAE,CAAIA,CAAAA,CAAAA,CAAI,CACtB,CAAA,CAAA,CAAA,CAAC,CAIH,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAASoC,CAAImD,CAAAA,CAAAA,CAAM,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAGnD,CAAI,CAAA,CAAA,CAAG,CAAEA,CAAAA,CAAAA,CAAG,CACzC,CAAMoD,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAKpD,CAAI,CAAA,CAAA,CAAA,CAAM,CACfqD,CAAAA,CAAAA,CAAIrD,CACVmD,CAAAA,CAAAA,CAAMC,CAAC,CAAID,CAAAA,CAAAA,CAAMC,CAAC,CAAA,CACf,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMD,CAAME,CAAAA,CAAC,CAAC,CACnB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CACJd,CAAAA,CAAAA,CAAAA,CAAAA,CAAkCW,CAAQE,CAAAA,CAAC,CAAG,CAAA,CAC5C,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACN,CAAAA,CAAAA,CAAAA,CACA,CAAAC,CAAAA,CAAAA,CACA,CAAAL,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACA,MAAAD,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAD,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAG,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA/C,CACF,CAAC,CACH,CACC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMtC,CAAQ,CAAA,CAAA,CACb,CAAWiC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAMjC,CAAI,CAAA,CAAA,CAAA,CAAA,CACnBsC,EAAML,CAAE,CAAA,CAAIjC,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMiC,CAAE,CAE5B,CAAC,CACL,CAGA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAASG,CAAI,CAAA,CAAA,CAAGA,CAAI2C,CAAAA,CAAAA,CAAY,CAAE3C,CAAAA,CAAAA,CAChCmD,EAAMnD,CAAC,CAAA,CAAImD,CAAMnD,CAAAA,CAAC,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAMkD,CAAAA,CAAAA,CAAAA,CAAAA,CAAQlD,CAAC,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAW,CAAA,CAAA,CAIvD,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAImD,CAAAA,CAAAA,CAAAA,CAAK,EAGvB,CAAMG,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAMC,CAAkBX,CAAAA,CAAAA,CAAS,CACrC,CAAA,CAAA,CAAIA,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAI,CAAA,CAAA,CAAI,CAC7B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CACP,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAe5G,CACjB,CAAA,CAAC,EACKwB,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAY5B,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAoB,CACtD0H,CAAAA,CAAAA,CAAI,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,EACbnC,CAAMjB,CAAAA,CAAAA,CAAAA,CAAO1C,CAAQ,CAAA,CAAA,CAAG8F,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAME,CAAY,CAAA,CAC/CF,EAAI,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAK,CAEb,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAASE,CACPnC,CAAAA,CAAAA,CACAoC,CACAC,CAAAA,CAAAA,CACAC,CACM,CAAA,CACN,CAAMC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAM,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMX,CAAKU,CAAAA,CAAAA,CAAAA,CAAM,CAAC,CAAA,CAAIX,CAAOW,CAAAA,CAAAA,CAAAA,CAAM,CAAC,CAAC,CACtDtC,CAAAA,CAAAA,CAAO,CAAMoC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAK,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAGC,CAAAA,CAAO,CAAC,CAAA,CAC9CrC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAG,CAAA,CAAA,CAAA,CAChBA,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAOyB,CAAKa,CAAAA,CAAAA,CAAAA,CAAM,CAAC,CAAA,CAAI,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAC,CAAC,CAC5CtC,CAAAA,CAAAA,CAAO,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAChBA,CAAAA,CAAAA,CAAO,CAAOuC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAM,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAC,CAAC,CAClCvC,CAAAA,CAAAA,CAAO,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,EAChBA,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO0B,CAAMY,CAAAA,CAAAA,CAAAA,CAAM,CAAC,CAAA,CAAI,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAC,CAAC,CAC/C,CACF,OChIaE,CAAe,CAAA,CAAA,CAAA,CAAKrH,CACpBsH,CAAAA,CAAAA,CAAgB,CAAMtH,CAAAA,CAAAA,CAAAA,CAAAA,CAO5B,CAASuH,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAYV,CAAWxG,CAAAA,CAAAA,CAAaC,CAAqB,CAAA,CACvE,CAAIuG,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAExG,CAAG,CAAA,CAAA,CAAA,CAAMR,CACb,CAAA,CAAA,CAAA,CAAA,CAAEQ,EACKA,CAAM,CAAA,CAAA,CAAIC,CACb,CAAA,CAAA,CAAE,CAAKuG,CAAAA,CAAAA,CAAAA,CAAExG,CAAG,CAAA,CAAIwG,CAAExG,CAAAA,CAAAA,CAAM,CAAC,CAAA,CAAIgH,CAC7B,CAAA,CAAA,CAAA,CAAE,CAAMR,CAAAA,CAAAA,CAAAA,CAAAA,CAAExG,CAAG,CAAA,CAAI,CAAKwG,CAAAA,CAAAA,CAAAA,CAAExG,CAAM,CAAA,CAAC,CAAIwG,CAAAA,CAAAA,CAAExG,CAAM,CAAA,CAAC,CAAIiH,CAAAA,CAAAA,CAAAA,CAAAA,CAE/CjH,CAAM,CAAA,CAAA,CAAIC,CACb,CAAA,CAAA,CAAA,CAAKuG,EAAExG,CAAG,CAAA,CAAIwG,CAAExG,CAAAA,CAAAA,CAAM,CAAC,CAAA,CAAIgH,CAC3B,CAAA,CAAA,CAAA,CAAA,CAAMR,CAAExG,CAAAA,CAAG,CAAI,CAAA,CAAA,CAAA,CAAKwG,CAAExG,CAAAA,CAAAA,CAAM,CAAC,CAAA,CAAIwG,CAAExG,CAAAA,CAAAA,CAAM,CAAC,CAAA,CAAIiH,CACpD,CCLA,CAAsBpB,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAI,CACxB,CAAA,CAAA,CAAA,CAAA/E,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAX,CACA,CAAA,CAAA,CAAA,CAAA6C,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAnC,CAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAsF,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAD,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAD,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAG,CACF,CAAA,CAA6C,CAE3C,CAAA,CAAA,CAAIvF,CAASC,CAAAA,CAAAA,CAAAA,CACX,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAoB,CAAAkC,CAAAA,CAAAA,CAAAA,CAAI,CAAMD,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAWC,CAAI,CAAA,CAAC,CAAE,CAAA,CAIjE,CAAIN,CAAAA,CAAAA,CAAAA,CAAAA,CAAOK,CAAWC,CAAAA,CAAE,CACpBmE,CAAAA,CAAAA,CAAWnE,EAAKlE,CAAe,CAAA,CAAA,CACnC,CAAM6B,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAS,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAY3B,CAAa,CAAA,CAGzCwF,CAAS4C,CAAAA,CAAAA,CAAiBjH,CAAU,CAAA,CACxC,CAAAU,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACA,CAAKC,CAAAA,CAAAA,CAAAA,CAAAA,CAAM,CACX,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAeG,CAAiBH,CAAAA,CAAAA,CAAAA,CAAMD,CAAK,CAC7C,CAAC,CAAA,CAGD,CAAIwG,CAAAA,CAAAA,CAAAA,CAAAA,CAAO,CACPC,CAAAA,CAAAA,CACJ,CAAiBC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAS/C,CAAQ,CAAA,CAEhC,MAAMgD,CAAID,CAAAA,CAAAA,CAAM,CAChB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAASpE,CAAI,CAAA,CAAA,CAAGA,CAAIqE,CAAAA,CAAAA,CAAG,CAAErE,CAAAA,CAAAA,CAAG,CAE1B,CAAA,CAAA,CAAIoE,CAAMpE,CAAAA,CAAC,CAAM1D,CAAAA,CAAAA,CAAAA,CAAAA,CAAc,CAC7BkB,CAAAA,CAAO0G,CAAM,CAAA,CAAA,CAAA,CAAIE,CAAMpE,CAAAA,CAAC,CACxB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACF,CAGA,CAAA,CAAA,CAAA,CAAIsE,CAAOJ,CAAAA,CAAAA,CAAO,CACd1G,CAAAA,CAAAA,CAAO8G,CAAO,CAAA,CAAC,IAAM/H,CACvB+H,CAAAA,CAAAA,CAAAA,CAAQ,CACC9G,CAAAA,CAAAA,CAAO8G,CAAO,CAAA,CAAC,CAAM/H,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAC9B+H,CAAQ,CAAA,CAAA,CAAA,CAAA,CAIV,CAAMC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAQR,CAAYvG,CAAAA,CAAAA,CAAAA,CAAQ8G,CAAO,CAAA,CAAA,CAAGJ,CAAI,CAAA,CAChDA,CAAO,CAAA,CAAA,CAGP,CAAC3E,CAAAA,CAAM4E,CAAI,CAAA,CAAI7E,CAAIC,CAAAA,CAAAA,CAAAA,CAAM/B,CAAQ,CAAA,CAAA,CAAG8G,CAAI,CAAA,CAGpC/E,CAAK4E,CAAAA,CAAAA,CAAO1F,CAAmB,CAAA,CAAA,CAAA,CAAMM,CAEvCyF,CAAAA,CAAAA,CAAcjF,CAAK4E,CAAAA,CAAAA,CAAO1F,CAAmB,CAAA,CAAG8F,CAAK,CAAA,CAAA,CAGrDhF,CAAK4E,CAAAA,CAAAA,CAAO1F,CAAmB,CAAA,CAAIuF,CACnCS,CAAAA,CAAAA,CAAWT,CAAYO,CAAAA,CAAAA,CAAAA,CAAK,CAEhC,CAAA,CACF,CAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAASE,CAAWhF,CAAAA,CAAAA,CAAeiF,CAAoB,CAAA,CACrD5B,CAAKrD,CAAAA,CAAAA,CAAAA,CAAS,CAAC,CAAA,CAAIiF,CACnB3B,CAAAA,CAAAA,CAAMtD,GAAS,CAAC,CAAA,CAAIiF,CACpB1B,CAAAA,CAAAA,CAAOvD,CAAS,CAAA,CAAA,CAAC,CAAI,CAAA,CAAA,CACrBwD,CAAKxD,CAAAA,CAAAA,CAAAA,CAAS,CAAC,CAAA,CAAIiF,CACrB,CAEA,CAASF,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAc/E,CAAeiF,CAAAA,CAAAA,CAAoB,CACxDjF,CAAAA,CAAAA,CAAAA,CAAU,CACVqD,CAAAA,CAAAA,CAAKrD,CAAK,CAAA,CAAIqD,CAAKrD,CAAAA,CAAK,CAAKiF,CAAAA,CAAAA,CAAAA,CAAO5B,CAAKrD,CAAAA,CAAK,CAAIiF,CAAAA,CAAAA,CAClD3B,EAAMtD,CAAK,CAAA,CAAIsD,CAAMtD,CAAAA,CAAK,CAAKiF,CAAAA,CAAAA,CAAAA,CAAO3B,CAAMtD,CAAAA,CAAK,CAAIiF,CAAAA,CAAAA,CACrD,CAAE1B,CAAAA,CAAAA,CAAOvD,CAAS,CAAA,CAAA,CAAC,CACnBwD,CAAAA,CAAAA,CAAKxD,CAAS,CAAA,CAAA,CAAC,CAAKiF,CAAAA,CAAAA,CACtB,CAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAE,CAAA,CAAA,CAAA,CAAA,CAAM,CAAoB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA7E,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAN,CAAK,CAC9C,CAEO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAASoF,GAAM,CACpB,CAAA,CAAAvB,CACA,CAAA,CAAA,CAAAC,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAnD,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA8C,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAD,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAD,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAG,CACF,CAAA,CAAgC,CAC9B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS2B,CAAclE,CAAAA,CAAAA,CAAYC,CAAkB,CAAA,CACnDD,CAAO,CAAA,CAAA,CAAA,CAAA,CACPC,CAAO,CAAA,CAAA,CAAA,CAAA,CACPmC,CAAKpC,CAAAA,CAAE,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAIoC,CAAAA,CAAAA,CAAAA,CAAAA,CAAKpC,CAAE,CAAGoC,CAAAA,CAAAA,CAAKnC,CAAE,CAAC,CACtCoC,CAAAA,CAAAA,CAAMrC,CAAE,CAAA,CAAI,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAIqC,CAAMrC,CAAAA,CAAE,CAAGqC,CAAAA,CAAAA,CAAMpC,CAAE,CAAC,CACzCqC,CAAAA,CAAAA,CAAOtC,CAAM,CAAA,CAAA,CAAC,CAAKsC,CAAAA,CAAAA,CAAAA,CAAOrC,CAAM,CAAA,CAAA,CAAC,CACjCsC,CAAAA,CAAAA,CAAKvC,CAAM,CAAA,CAAA,CAAC,CAAKuC,CAAAA,CAAAA,CAAAA,CAAKtC,CAAM,CAAA,CAAA,CAAC,CAC/B,CAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAE,CAAA,CAAA,CAAA,CAAA,CAAM,CAAkB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CADrBV,CAAUC,CAAAA,CAAAA,CAAAA,CAAOkD,CAAGC,CAAAA,CAAAA,CAAGuB,CAAa,CAAA,CACV,CAAA1E,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAM,CAC9C,CC9GA,CAAI2E,CAAAA,CAAAA,CAAAA,CAAc,CAChB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM3C,CAAa4C,CAAAA,CAAAA,CAAc,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAChDC,CAAAA,CAAAA,CAAAA,CAAQ,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAC,CAAA,CAAG7C,CAAY8C,CAAAA,CAAAA,CAAqB,CAAC,CAC7D,CAAA,CAAA,CAAA,CAAA,CAAA,CACEC,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAY,CAAW,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAOC,CAAiB,CAAA,CAAA,CACzD,CAAIA,CAAAA,CAAAA,CAAAA,CAAI,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACfD,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAY,CAAME,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAUD,CAAqB,CAAC,CACrDA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAI,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACtBD,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAYN,CAAMO,CAAAA,CAAAA,CAAmB,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAE5C,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAsB,CAE1C,CAAC,CAAA,CAAA;"} \ No newline at end of file +{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/constants/utf8.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/utils/parse.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n *\n * @remarks\n *\n * Changing this value affects the `count` and\n * `sum` values used for calculating a station's\n * average temperature.\n *\n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n *\n * @remarks\n *\n * Changing this value affects the `min`, `max` and `sum` values\n * used for calculating a station's min, max and avg\n * temperatures, respectively.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n *\n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n *\n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n *\n * @remarks\n *\n * This limit should be sufficient for most use cases.\n * However, feel free to adjust up or down as needed.\n *\n * There is not much basis for the current value.\n * Development was done with at most 8 workers and\n * a reasonable input file, with memory never exceeding\n * 20 MiB total across all workers.\n *\n * In theory, the challenge constraints allow for input\n * files that would require each worker using upwards of\n * 800 MiB; 10K stations with completely unique 100 byte names,\n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = trie[index /*+ TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index /*+ TRIE_PTR_IDX_IDX*/] = child;\n // Initialize node\n trie[child /* + TRIE_NODE_ID_IDX*/] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr /* + TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child /* + TRIE_NODE_ID_IDX*/];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi /* + TRIE_PTR_IDX_IDX*/];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri /*+ TRIE_NODE_ID_IDX*/];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai /*+ TRIE_PTR_IDX_IDX*/];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai /*+ TRIE_PTR_IDX_IDX*/] = li;\n // Initialize redirect\n tries[at][li /* + TRIE_XPTR_ID_IDX*/] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li /* + TRIE_NODE_ID_IDX*/];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr /* + TRIE_PTR_IDX_IDX*/];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI /* + TRIE_NODE_ID_IDX*/];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { CHAR_MINUS, CHAR_ZERO } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CHAR_MINUS);\n b[min + ~sign] = CHAR_ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CHAR_MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { parseDouble } from \"./utils/parse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CHAR_NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 4;\n if (buffer[semI - 2] === CHAR_SEMICOLON) {\n semI -= 2;\n } else if (buffer[semI - 1] === CHAR_SEMICOLON) {\n semI -= 1;\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Request } from \"./types/request\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === \"process\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","MIN_WORKERS","MAX_WORKERS","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","CHAR_ZERO_11","CHAR_ZERO_111","parseDouble","stations","createReadStream","bufI","leaf","chunk","N","semI","tempV","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/src/index.ts b/src/main/nodejs/havelessbemore/src/index.ts index 4bbc0de..baacd07 100644 --- a/src/main/nodejs/havelessbemore/src/index.ts +++ b/src/main/nodejs/havelessbemore/src/index.ts @@ -4,7 +4,7 @@ import { isMainThread, parentPort } from "node:worker_threads"; import { run as runMain } from "./main"; import { merge, run as runWorker } from "./worker"; -import { Message } from "./types/message"; +import { Request } from "./types/request"; import { ProcessRequest } from "./types/processRequest"; import { MergeRequest } from "./types/mergeRequest"; @@ -12,10 +12,10 @@ if (isMainThread) { const workerPath = fileURLToPath(import.meta.url); runMain(process.argv[2], workerPath, availableParallelism()); } else { - parentPort!.addListener("message", async (msg: Message) => { - if (msg.type === "process_request") { + parentPort!.addListener("message", async (msg: Request) => { + if (msg.type === "process") { parentPort!.postMessage(await runWorker(msg as ProcessRequest)); - } else if (msg.type === "merge_request") { + } else if (msg.type === "merge") { parentPort!.postMessage(merge(msg as MergeRequest)); } else { throw new Error("Unknown message type"); diff --git a/src/main/nodejs/havelessbemore/src/main.ts b/src/main/nodejs/havelessbemore/src/main.ts index 27d7f8b..91506a4 100644 --- a/src/main/nodejs/havelessbemore/src/main.ts +++ b/src/main/nodejs/havelessbemore/src/main.ts @@ -55,7 +55,7 @@ export async function run( const tasks = new Array>(maxWorkers); for (let i = 0; i < maxWorkers; ++i) { tasks[i] = exec(workers[i], { - type: "process_request", + type: "process", counts, end: chunks[i][1], filePath, @@ -77,7 +77,7 @@ export async function run( .then(() => tasks[b]) .then(() => exec(workers[a], { - type: "merge_request", + type: "merge", a, b, counts, diff --git a/src/main/nodejs/havelessbemore/src/types/mergeRequest.ts b/src/main/nodejs/havelessbemore/src/types/mergeRequest.ts index dfeda60..b58428a 100644 --- a/src/main/nodejs/havelessbemore/src/types/mergeRequest.ts +++ b/src/main/nodejs/havelessbemore/src/types/mergeRequest.ts @@ -1,7 +1,7 @@ -import { Message } from "./message"; +import { Request } from "./request"; -export interface MergeRequest extends Message { - type: "merge_request"; +export interface MergeRequest extends Request { + type: "merge"; a: number; b: number; // Shared memory diff --git a/src/main/nodejs/havelessbemore/src/types/mergeResponse.ts b/src/main/nodejs/havelessbemore/src/types/mergeResponse.ts index b980857..2784f6e 100644 --- a/src/main/nodejs/havelessbemore/src/types/mergeResponse.ts +++ b/src/main/nodejs/havelessbemore/src/types/mergeResponse.ts @@ -1,7 +1,6 @@ -import { Message } from "./message"; +import { Response } from "./response"; -export interface MergeResponse extends Message { - type: "merge_response"; +export interface MergeResponse extends Response { ids: number[]; tries: Int32Array[]; } diff --git a/src/main/nodejs/havelessbemore/src/types/message.ts b/src/main/nodejs/havelessbemore/src/types/message.ts deleted file mode 100644 index 687654b..0000000 --- a/src/main/nodejs/havelessbemore/src/types/message.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface Message { - type: string; -} diff --git a/src/main/nodejs/havelessbemore/src/types/processRequest.ts b/src/main/nodejs/havelessbemore/src/types/processRequest.ts index eb6c4cd..6fa5087 100644 --- a/src/main/nodejs/havelessbemore/src/types/processRequest.ts +++ b/src/main/nodejs/havelessbemore/src/types/processRequest.ts @@ -1,7 +1,7 @@ -import { Message } from "./message"; +import { Request } from "./request"; -export interface ProcessRequest extends Message { - type: "process_request"; +export interface ProcessRequest extends Request { + type: "process"; end: number; filePath: string; id: number; diff --git a/src/main/nodejs/havelessbemore/src/types/processResponse.ts b/src/main/nodejs/havelessbemore/src/types/processResponse.ts index c12c521..537fd76 100644 --- a/src/main/nodejs/havelessbemore/src/types/processResponse.ts +++ b/src/main/nodejs/havelessbemore/src/types/processResponse.ts @@ -1,7 +1,6 @@ -import { Message } from "./message"; +import { Response } from "./response"; -export interface ProcessResponse extends Message { - type: "process_response"; +export interface ProcessResponse extends Response { id: number; trie: Int32Array; } diff --git a/src/main/nodejs/havelessbemore/src/types/request.ts b/src/main/nodejs/havelessbemore/src/types/request.ts new file mode 100644 index 0000000..021468f --- /dev/null +++ b/src/main/nodejs/havelessbemore/src/types/request.ts @@ -0,0 +1,3 @@ +export interface Request { + type: string; +} diff --git a/src/main/nodejs/havelessbemore/src/types/response.ts b/src/main/nodejs/havelessbemore/src/types/response.ts new file mode 100644 index 0000000..07f033b --- /dev/null +++ b/src/main/nodejs/havelessbemore/src/types/response.ts @@ -0,0 +1,3 @@ +export interface Response { +} + \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/src/worker.ts b/src/main/nodejs/havelessbemore/src/worker.ts index eeab789..0dd3297 100644 --- a/src/main/nodejs/havelessbemore/src/worker.ts +++ b/src/main/nodejs/havelessbemore/src/worker.ts @@ -26,7 +26,7 @@ export async function run({ }: ProcessRequest): Promise { // Check chunk size if (start >= end) { - return { type: "process_response", id, trie: createTrie(id, 0) }; + return { id, trie: createTrie(id, 0) }; } // Initialize constants @@ -96,7 +96,7 @@ export async function run({ sums[index >> 2] += temp; } - return { type: "process_response", id, trie }; + return { id, trie }; } export function merge({ @@ -117,5 +117,5 @@ export function merge({ sums[ai >> 2] += sums[bi >> 2]; } const ids = mergeLeft(tries, a, b, mergeStations); - return { type: "merge_response", ids, tries }; + return { ids, tries }; } From 526a9367ba4d0a938270702fcc2cad43557e7821 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Fri, 24 May 2024 22:20:00 -0400 Subject: [PATCH 35/69] Refactor parseDouble --- src/main/nodejs/havelessbemore/dist/index.cjs | 2 +- src/main/nodejs/havelessbemore/dist/index.cjs.map | 2 +- src/main/nodejs/havelessbemore/dist/index.mjs | 2 +- src/main/nodejs/havelessbemore/dist/index.mjs.map | 2 +- src/main/nodejs/havelessbemore/src/utils/parse.ts | 4 ++-- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs b/src/main/nodejs/havelessbemore/dist/index.cjs index 93cc051..3eb6799 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs +++ b/src/main/nodejs/havelessbemore/dist/index.cjs @@ -25,5 +25,5 @@ */ "use strict";var V=require("node:os"),j=require("node:url"),D=require("node:worker_threads"),L=require("node:fs"),z=require("fs/promises"),J=require("worker_threads"),X=typeof document<"u"?document.currentScript:null;const U=1e4,Q=100,x=107,ee=16384,te=1048576,re=1048576,ne=152e-6,oe=16384,ae=1,se=512,ie=45,P=10,W=59,C=48,k=32,_e=216;function v(e,n,r){return e>n?e<=r?e:r:n}async function ce(e,n,r,l=0){const i=await z.open(e);try{const a=(await i.stat()).size,f=Math.max(l,Math.floor(a/n)),u=Buffer.allocUnsafe(r),o=[];let s=0;for(let c=f;c=0&&_e.length&&(e=Z(e,a+S)),e[g]+=S,e[i]=a,e[a]=e[b]),i=a}return[e,i]}function K(e=0,n=Ee){n=Math.max(q,n);const r=new Int32Array(new SharedArrayBuffer(n<<2));return r[g]=q,r[b]=e,r}function Z(e,n=0){const r=e[g];n=Math.max(n,Math.ceil(r*fe));const l=new Int32Array(new SharedArrayBuffer(n<<2));for(let i=0;ie[o].length&&(e[o]=Z(e[o],t+H),i.add(o)),e[o][g]+=H,e[o][s]=t,e[o][t]=w,e[o][t+O]=R;else{const E=e[o][t];o!==E&&(t=e[o][t+O]),a.push([E,t,w,R])}}s+=p,I+=p}}a.splice(0,f)}while(a.length>0);return Array.from(i)}function ge(e,n,r,l,i="",a){const f=new Array(n.length+1);f[0]=[r,N+y,0];let u=0,o=!1;do{let[s,c,I]=f[u];if(I>=F){--u;continue}f[u][1]+=p,++f[u][2];let _=e[s][c];if(_===h)continue;const T=e[s][_];s!==T&&(_=e[s][_+O],s=T),n[u]=I+k,f[++u]=[s,_+y,0];const R=e[s][_+m];R!==h&&(o&&l.write(i),o=!0,a(l,n,u,R))}while(u>=0)}function ye(e){const n=new J.Worker(e);return n.on("error",r=>{throw r}),n.on("messageerror",r=>{throw r}),n.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${n.threadId} exited with code ${r}`)}),n}function G(e,n){return new Promise(r=>{e.once("message",r),e.postMessage(n)})}async function Ne(e,n,r,l=""){r=v(r,ae,se);const i=await ce(e,r,x,oe);r=i.length;const a=new SharedArrayBuffer(U*r+1<<4),f=new Int16Array(a),u=new Int16Array(a,2),o=new Uint32Array(a,4),s=new Float64Array(a,8),c=new Array(r),I=new Array(r);for(let t=0;t{c[E.id]=E.trie});for(let t=_.length-1;t>0;--t){const E=t-1>>1,d=t;_[E]=_[E].then(()=>_[d]).then(()=>G(I[E],{type:"merge",a:E,b:d,counts:o,maxes:u,mins:f,sums:s,tries:c})).then(M=>{for(const A of M.ids)c[A]=M.tries[A]})}for(let t=0;tI[t].terminate());await Promise.all(_);const T=L.createWriteStream(l,{fd:l.length<1?1:void 0,flags:"a",highWaterMark:re}),R=Buffer.allocUnsafe(Q);T.write("{"),ge(c,R,0,T,", ",w),T.end(`} -`);function w(t,E,d,M){const A=Math.round(s[M<<1]/o[M<<2]);t.write(E.toString("utf8",0,d)),t.write("="),t.write((f[M<<3]/10).toFixed(1)),t.write("/"),t.write((A/10).toFixed(1)),t.write("/"),t.write((u[M<<3]/10).toFixed(1))}}const Y=11*C,$=111*C;function De(e,n,r){return e[n]===ie?(++n,n+4>r?-(10*e[n]+e[n+2]-Y):-(100*e[n]+10*e[n+1]+e[n+3]-$)):n+4>r?10*e[n]+e[n+2]-Y:100*e[n]+10*e[n+1]+e[n+3]-$}async function pe({end:e,filePath:n,id:r,start:l,counts:i,maxes:a,mins:f,sums:u}){if(l>=e)return{id:r,trie:K(r,0)};let o=K(r),s=r*U+1;const c=Buffer.allocUnsafe(x),I=L.createReadStream(n,{start:l,end:e-1,highWaterMark:ue(e-l)});let _=0,T;for await(const t of I){const E=t.length;for(let d=0;d=E?a[t]:E,++i[t>>1],u[t>>2]+=E}return{id:r,trie:o}}function Oe({a:e,b:n,tries:r,counts:l,maxes:i,mins:a,sums:f}){function u(o,s){o<<=3,s<<=3,a[o]=Math.min(a[o],a[s]),i[o]=Math.max(i[o],i[s]),l[o>>1]+=l[s>>1],f[o>>2]+=f[s>>2]}return{ids:me(r,e,n,u),tries:r}}if(D.isMainThread){const e=j.fileURLToPath(typeof document>"u"?require("url").pathToFileURL(__filename).href:X&&X.src||new URL("index.cjs",document.baseURI).href);Ne(process.argv[2],e,V.availableParallelism())}else D.parentPort.addListener("message",async e=>{if(e.type==="process")D.parentPort.postMessage(await pe(e));else if(e.type==="merge")D.parentPort.postMessage(Oe(e));else throw new Error("Unknown message type")}); +`);function w(t,E,d,M){const A=Math.round(s[M<<1]/o[M<<2]);t.write(E.toString("utf8",0,d)),t.write("="),t.write((f[M<<3]/10).toFixed(1)),t.write("/"),t.write((A/10).toFixed(1)),t.write("/"),t.write((u[M<<3]/10).toFixed(1))}}const Y=11*C,$=111*C;function De(e,n,r){return e[n]===ie?(++n,n+4>r?Y-10*e[n]-e[n+2]:$-100*e[n]-10*e[n+1]-e[n+3]):n+4>r?10*e[n]+e[n+2]-Y:100*e[n]+10*e[n+1]+e[n+3]-$}async function pe({end:e,filePath:n,id:r,start:l,counts:i,maxes:a,mins:f,sums:u}){if(l>=e)return{id:r,trie:K(r,0)};let o=K(r),s=r*U+1;const c=Buffer.allocUnsafe(x),I=L.createReadStream(n,{start:l,end:e-1,highWaterMark:ue(e-l)});let _=0,T;for await(const t of I){const E=t.length;for(let d=0;d=E?a[t]:E,++i[t>>1],u[t>>2]+=E}return{id:r,trie:o}}function Oe({a:e,b:n,tries:r,counts:l,maxes:i,mins:a,sums:f}){function u(o,s){o<<=3,s<<=3,a[o]=Math.min(a[o],a[s]),i[o]=Math.max(i[o],i[s]),l[o>>1]+=l[s>>1],f[o>>2]+=f[s>>2]}return{ids:me(r,e,n,u),tries:r}}if(D.isMainThread){const e=j.fileURLToPath(typeof document>"u"?require("url").pathToFileURL(__filename).href:X&&X.src||new URL("index.cjs",document.baseURI).href);Ne(process.argv[2],e,V.availableParallelism())}else D.parentPort.addListener("message",async e=>{if(e.type==="process")D.parentPort.postMessage(await pe(e));else if(e.type==="merge")D.parentPort.postMessage(Oe(e));else throw new Error("Unknown message type")}); //# sourceMappingURL=index.cjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs.map b/src/main/nodejs/havelessbemore/dist/index.cjs.map index 4ed87f7..3cda020 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.cjs.map @@ -1 +1 @@ -{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/constants/utf8.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/utils/parse.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n *\n * @remarks\n *\n * Changing this value affects the `count` and\n * `sum` values used for calculating a station's\n * average temperature.\n *\n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n *\n * @remarks\n *\n * Changing this value affects the `min`, `max` and `sum` values\n * used for calculating a station's min, max and avg\n * temperatures, respectively.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n *\n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n *\n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n *\n * @remarks\n *\n * This limit should be sufficient for most use cases.\n * However, feel free to adjust up or down as needed.\n *\n * There is not much basis for the current value.\n * Development was done with at most 8 workers and\n * a reasonable input file, with memory never exceeding\n * 20 MiB total across all workers.\n *\n * In theory, the challenge constraints allow for input\n * files that would require each worker using upwards of\n * 800 MiB; 10K stations with completely unique 100 byte names,\n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = trie[index /*+ TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index /*+ TRIE_PTR_IDX_IDX*/] = child;\n // Initialize node\n trie[child /* + TRIE_NODE_ID_IDX*/] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr /* + TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child /* + TRIE_NODE_ID_IDX*/];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi /* + TRIE_PTR_IDX_IDX*/];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri /*+ TRIE_NODE_ID_IDX*/];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai /*+ TRIE_PTR_IDX_IDX*/];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai /*+ TRIE_PTR_IDX_IDX*/] = li;\n // Initialize redirect\n tries[at][li /* + TRIE_XPTR_ID_IDX*/] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li /* + TRIE_NODE_ID_IDX*/];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr /* + TRIE_PTR_IDX_IDX*/];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI /* + TRIE_NODE_ID_IDX*/];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { CHAR_MINUS, CHAR_ZERO } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CHAR_MINUS);\n b[min + ~sign] = CHAR_ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CHAR_MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { parseDouble } from \"./utils/parse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CHAR_NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 4;\n if (buffer[semI - 2] === CHAR_SEMICOLON) {\n semI -= 2;\n } else if (buffer[semI - 1] === CHAR_SEMICOLON) {\n semI -= 1;\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Request } from \"./types/request\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === \"process\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","MIN_WORKERS","MAX_WORKERS","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","CHAR_ZERO_11","CHAR_ZERO_111","parseDouble","stations","createReadStream","bufI","leaf","chunk","N","semI","tempV","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","_documentCurrentScript","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/constants/utf8.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/utils/parse.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n *\n * @remarks\n *\n * Changing this value affects the `count` and\n * `sum` values used for calculating a station's\n * average temperature.\n *\n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n *\n * @remarks\n *\n * Changing this value affects the `min`, `max` and `sum` values\n * used for calculating a station's min, max and avg\n * temperatures, respectively.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n *\n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n *\n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n *\n * @remarks\n *\n * This limit should be sufficient for most use cases.\n * However, feel free to adjust up or down as needed.\n *\n * There is not much basis for the current value.\n * Development was done with at most 8 workers and\n * a reasonable input file, with memory never exceeding\n * 20 MiB total across all workers.\n *\n * In theory, the challenge constraints allow for input\n * files that would require each worker using upwards of\n * 800 MiB; 10K stations with completely unique 100 byte names,\n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = trie[index /*+ TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index /*+ TRIE_PTR_IDX_IDX*/] = child;\n // Initialize node\n trie[child /* + TRIE_NODE_ID_IDX*/] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr /* + TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child /* + TRIE_NODE_ID_IDX*/];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi /* + TRIE_PTR_IDX_IDX*/];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri /*+ TRIE_NODE_ID_IDX*/];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai /*+ TRIE_PTR_IDX_IDX*/];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai /*+ TRIE_PTR_IDX_IDX*/] = li;\n // Initialize redirect\n tries[at][li /* + TRIE_XPTR_ID_IDX*/] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li /* + TRIE_NODE_ID_IDX*/];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr /* + TRIE_PTR_IDX_IDX*/];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI /* + TRIE_NODE_ID_IDX*/];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { CHAR_MINUS, CHAR_ZERO } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CHAR_MINUS);\n b[min + ~sign] = CHAR_ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CHAR_MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { parseDouble } from \"./utils/parse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CHAR_NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 4;\n if (buffer[semI - 2] === CHAR_SEMICOLON) {\n semI -= 2;\n } else if (buffer[semI - 1] === CHAR_SEMICOLON) {\n semI -= 1;\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Request } from \"./types/request\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === \"process\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","MIN_WORKERS","MAX_WORKERS","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","CHAR_ZERO_11","CHAR_ZERO_111","parseDouble","stations","createReadStream","bufI","leaf","chunk","N","semI","tempV","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","_documentCurrentScript","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index a656b42..79ce98c 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -25,5 +25,5 @@ */ import{availableParallelism as $}from"node:os";import{fileURLToPath as V}from"node:url";import{isMainThread as z,parentPort as H}from"node:worker_threads";import{createWriteStream as j,createReadStream as q}from"node:fs";import{open as J}from"fs/promises";import{Worker as Q}from"worker_threads";const X=1e4,tt=100,L=107,et=16384,rt=1048576,nt=1048576,ot=152e-6,at=16384,st=1,it=512,_t=45,x=10,U=59,W=48,P=32,ct=216;function C(t,n,r){return t>n?t<=r?t:r:n}async function Et(t,n,r,I=0){const i=await J(t);try{const a=(await i.stat()).size,l=Math.max(I,Math.floor(a/n)),E=Buffer.allocUnsafe(r),o=[];let s=0;for(let c=l;c=0&&_t.length&&(t=b(t,a+p)),t[g]+=p,t[i]=a,t[a]=t[B]),i=a}return[t,i]}function Z(t=0,n=lt){n=Math.max(K,n);const r=new Int32Array(new SharedArrayBuffer(n<<2));return r[g]=K,r[B]=t,r}function b(t,n=0){const r=t[g];n=Math.max(n,Math.ceil(r*It));const I=new Int32Array(new SharedArrayBuffer(n<<2));for(let i=0;it[o].length&&(t[o]=b(t[o],e+S),i.add(o)),t[o][g]+=S,t[o][s]=e,t[o][e]=w,t[o][e+O]=R;else{const f=t[o][e];o!==f&&(e=t[o][e+O]),a.push([f,e,w,R])}}s+=D,u+=D}}a.splice(0,l)}while(a.length>0);return Array.from(i)}function Nt(t,n,r,I,i="",a){const l=new Array(n.length+1);l[0]=[r,y+N,0];let E=0,o=!1;do{let[s,c,u]=l[E];if(u>=F){--E;continue}l[E][1]+=D,++l[E][2];let _=t[s][c];if(_===m)continue;const T=t[s][_];s!==T&&(_=t[s][_+O],s=T),n[E]=u+P,l[++E]=[s,_+N,0];const R=t[s][_+d];R!==m&&(o&&I.write(i),o=!0,a(I,n,E,R))}while(E>=0)}function yt(t){const n=new Q(t);return n.on("error",r=>{throw r}),n.on("messageerror",r=>{throw r}),n.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${n.threadId} exited with code ${r}`)}),n}function G(t,n){return new Promise(r=>{t.once("message",r),t.postMessage(n)})}async function Dt(t,n,r,I=""){r=C(r,st,it);const i=await Et(t,r,L,at);r=i.length;const a=new SharedArrayBuffer(X*r+1<<4),l=new Int16Array(a),E=new Int16Array(a,2),o=new Uint32Array(a,4),s=new Float64Array(a,8),c=new Array(r),u=new Array(r);for(let e=0;e{c[f.id]=f.trie});for(let e=_.length-1;e>0;--e){const f=e-1>>1,h=e;_[f]=_[f].then(()=>_[h]).then(()=>G(u[f],{type:"merge",a:f,b:h,counts:o,maxes:E,mins:l,sums:s,tries:c})).then(M=>{for(const A of M.ids)c[A]=M.tries[A]})}for(let e=0;eu[e].terminate());await Promise.all(_);const T=j(I,{fd:I.length<1?1:void 0,flags:"a",highWaterMark:nt}),R=Buffer.allocUnsafe(tt);T.write("{"),Nt(c,R,0,T,", ",w),T.end(`} -`);function w(e,f,h,M){const A=Math.round(s[M<<1]/o[M<<2]);e.write(f.toString("utf8",0,h)),e.write("="),e.write((l[M<<3]/10).toFixed(1)),e.write("/"),e.write((A/10).toFixed(1)),e.write("/"),e.write((E[M<<3]/10).toFixed(1))}}const v=11*W,Y=111*W;function Ot(t,n,r){return t[n]===_t?(++n,n+4>r?-(10*t[n]+t[n+2]-v):-(100*t[n]+10*t[n+1]+t[n+3]-Y)):n+4>r?10*t[n]+t[n+2]-v:100*t[n]+10*t[n+1]+t[n+3]-Y}async function pt({end:t,filePath:n,id:r,start:I,counts:i,maxes:a,mins:l,sums:E}){if(I>=t)return{id:r,trie:Z(r,0)};let o=Z(r),s=r*X+1;const c=Buffer.allocUnsafe(L),u=q(n,{start:I,end:t-1,highWaterMark:ft(t-I)});let _=0,T;for await(const e of u){const f=e.length;for(let h=0;h=f?a[e]:f,++i[e>>1],E[e>>2]+=f}return{id:r,trie:o}}function Ht({a:t,b:n,tries:r,counts:I,maxes:i,mins:a,sums:l}){function E(o,s){o<<=3,s<<=3,a[o]=Math.min(a[o],a[s]),i[o]=Math.max(i[o],i[s]),I[o>>1]+=I[s>>1],l[o>>2]+=l[s>>2]}return{ids:gt(r,t,n,E),tries:r}}if(z){const t=V(import.meta.url);Dt(process.argv[2],t,$())}else H.addListener("message",async t=>{if(t.type==="process")H.postMessage(await pt(t));else if(t.type==="merge")H.postMessage(Ht(t));else throw new Error("Unknown message type")}); +`);function w(e,f,h,M){const A=Math.round(s[M<<1]/o[M<<2]);e.write(f.toString("utf8",0,h)),e.write("="),e.write((l[M<<3]/10).toFixed(1)),e.write("/"),e.write((A/10).toFixed(1)),e.write("/"),e.write((E[M<<3]/10).toFixed(1))}}const v=11*W,Y=111*W;function Ot(t,n,r){return t[n]===_t?(++n,n+4>r?v-10*t[n]-t[n+2]:Y-100*t[n]-10*t[n+1]-t[n+3]):n+4>r?10*t[n]+t[n+2]-v:100*t[n]+10*t[n+1]+t[n+3]-Y}async function pt({end:t,filePath:n,id:r,start:I,counts:i,maxes:a,mins:l,sums:E}){if(I>=t)return{id:r,trie:Z(r,0)};let o=Z(r),s=r*X+1;const c=Buffer.allocUnsafe(L),u=q(n,{start:I,end:t-1,highWaterMark:ft(t-I)});let _=0,T;for await(const e of u){const f=e.length;for(let h=0;h=f?a[e]:f,++i[e>>1],E[e>>2]+=f}return{id:r,trie:o}}function Ht({a:t,b:n,tries:r,counts:I,maxes:i,mins:a,sums:l}){function E(o,s){o<<=3,s<<=3,a[o]=Math.min(a[o],a[s]),i[o]=Math.max(i[o],i[s]),I[o>>1]+=I[s>>1],l[o>>2]+=l[s>>2]}return{ids:gt(r,t,n,E),tries:r}}if(z){const t=V(import.meta.url);Dt(process.argv[2],t,$())}else H.addListener("message",async t=>{if(t.type==="process")H.postMessage(await pt(t));else if(t.type==="merge")H.postMessage(Ht(t));else throw new Error("Unknown message type")}); //# sourceMappingURL=index.mjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index 61a70c1..2ad0349 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1 +1 @@ -{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/constants/utf8.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/utils/parse.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n *\n * @remarks\n *\n * Changing this value affects the `count` and\n * `sum` values used for calculating a station's\n * average temperature.\n *\n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n *\n * @remarks\n *\n * Changing this value affects the `min`, `max` and `sum` values\n * used for calculating a station's min, max and avg\n * temperatures, respectively.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n *\n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n *\n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n *\n * @remarks\n *\n * This limit should be sufficient for most use cases.\n * However, feel free to adjust up or down as needed.\n *\n * There is not much basis for the current value.\n * Development was done with at most 8 workers and\n * a reasonable input file, with memory never exceeding\n * 20 MiB total across all workers.\n *\n * In theory, the challenge constraints allow for input\n * files that would require each worker using upwards of\n * 800 MiB; 10K stations with completely unique 100 byte names,\n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = trie[index /*+ TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index /*+ TRIE_PTR_IDX_IDX*/] = child;\n // Initialize node\n trie[child /* + TRIE_NODE_ID_IDX*/] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr /* + TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child /* + TRIE_NODE_ID_IDX*/];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi /* + TRIE_PTR_IDX_IDX*/];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri /*+ TRIE_NODE_ID_IDX*/];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai /*+ TRIE_PTR_IDX_IDX*/];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai /*+ TRIE_PTR_IDX_IDX*/] = li;\n // Initialize redirect\n tries[at][li /* + TRIE_XPTR_ID_IDX*/] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li /* + TRIE_NODE_ID_IDX*/];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr /* + TRIE_PTR_IDX_IDX*/];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI /* + TRIE_NODE_ID_IDX*/];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { CHAR_MINUS, CHAR_ZERO } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11)\n : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111);\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CHAR_MINUS);\n b[min + ~sign] = CHAR_ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CHAR_MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { parseDouble } from \"./utils/parse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CHAR_NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 4;\n if (buffer[semI - 2] === CHAR_SEMICOLON) {\n semI -= 2;\n } else if (buffer[semI - 1] === CHAR_SEMICOLON) {\n semI -= 1;\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Request } from \"./types/request\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === \"process\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","MIN_WORKERS","MAX_WORKERS","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","CHAR_ZERO_11","CHAR_ZERO_111","parseDouble","stations","createReadStream","bufI","leaf","chunk","N","semI","tempV","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/constants/utf8.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/utils/parse.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n *\n * @remarks\n *\n * Changing this value affects the `count` and\n * `sum` values used for calculating a station's\n * average temperature.\n *\n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n *\n * @remarks\n *\n * Changing this value affects the `min`, `max` and `sum` values\n * used for calculating a station's min, max and avg\n * temperatures, respectively.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n *\n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n *\n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n *\n * @remarks\n *\n * This limit should be sufficient for most use cases.\n * However, feel free to adjust up or down as needed.\n *\n * There is not much basis for the current value.\n * Development was done with at most 8 workers and\n * a reasonable input file, with memory never exceeding\n * 20 MiB total across all workers.\n *\n * In theory, the challenge constraints allow for input\n * files that would require each worker using upwards of\n * 800 MiB; 10K stations with completely unique 100 byte names,\n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = trie[index /*+ TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index /*+ TRIE_PTR_IDX_IDX*/] = child;\n // Initialize node\n trie[child /* + TRIE_NODE_ID_IDX*/] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr /* + TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child /* + TRIE_NODE_ID_IDX*/];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi /* + TRIE_PTR_IDX_IDX*/];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri /*+ TRIE_NODE_ID_IDX*/];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai /*+ TRIE_PTR_IDX_IDX*/];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai /*+ TRIE_PTR_IDX_IDX*/] = li;\n // Initialize redirect\n tries[at][li /* + TRIE_XPTR_ID_IDX*/] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li /* + TRIE_NODE_ID_IDX*/];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr /* + TRIE_PTR_IDX_IDX*/];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI /* + TRIE_NODE_ID_IDX*/];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { CHAR_MINUS, CHAR_ZERO } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CHAR_MINUS);\n b[min + ~sign] = CHAR_ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CHAR_MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { parseDouble } from \"./utils/parse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CHAR_NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 4;\n if (buffer[semI - 2] === CHAR_SEMICOLON) {\n semI -= 2;\n } else if (buffer[semI - 1] === CHAR_SEMICOLON) {\n semI -= 1;\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Request } from \"./types/request\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === \"process\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","MIN_WORKERS","MAX_WORKERS","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","CHAR_ZERO_11","CHAR_ZERO_111","parseDouble","stations","createReadStream","bufI","leaf","chunk","N","semI","tempV","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/src/utils/parse.ts b/src/main/nodejs/havelessbemore/src/utils/parse.ts index ac897b5..6391ef0 100644 --- a/src/main/nodejs/havelessbemore/src/utils/parse.ts +++ b/src/main/nodejs/havelessbemore/src/utils/parse.ts @@ -12,8 +12,8 @@ export function parseDouble(b: Buffer, min: number, max: number): number { if (b[min] === CHAR_MINUS) { ++min; return min + 4 > max - ? -(10 * b[min] + b[min + 2] - CHAR_ZERO_11) - : -(100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111); + ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2] + : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3]; } return min + 4 > max ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11 From c8b50277465a047b78789ecc06de60d4ca3dc7ff Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Fri, 24 May 2024 23:30:23 -0400 Subject: [PATCH 36/69] Refactor trie merging; Previously tries were merged as if they were part of a binary trie array, meaning each 'child' trie merged with its 'parent'. Now, tries are merged as they come in. Along with this, worker creation, work and termination have been merge into a single loop. --- src/main/nodejs/havelessbemore/dist/index.cjs | 4 +- .../nodejs/havelessbemore/dist/index.cjs.map | 2 +- src/main/nodejs/havelessbemore/dist/index.mjs | 4 +- .../nodejs/havelessbemore/dist/index.mjs.map | 2 +- src/main/nodejs/havelessbemore/src/main.ts | 52 +++++++------------ 5 files changed, 26 insertions(+), 38 deletions(-) diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs b/src/main/nodejs/havelessbemore/dist/index.cjs index 3eb6799..36eef50 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs +++ b/src/main/nodejs/havelessbemore/dist/index.cjs @@ -24,6 +24,6 @@ * SOFTWARE. */ -"use strict";var V=require("node:os"),j=require("node:url"),D=require("node:worker_threads"),L=require("node:fs"),z=require("fs/promises"),J=require("worker_threads"),X=typeof document<"u"?document.currentScript:null;const U=1e4,Q=100,x=107,ee=16384,te=1048576,re=1048576,ne=152e-6,oe=16384,ae=1,se=512,ie=45,P=10,W=59,C=48,k=32,_e=216;function v(e,n,r){return e>n?e<=r?e:r:n}async function ce(e,n,r,l=0){const i=await z.open(e);try{const a=(await i.stat()).size,f=Math.max(l,Math.floor(a/n)),u=Buffer.allocUnsafe(r),o=[];let s=0;for(let c=f;c=0&&_e.length&&(e=Z(e,a+S)),e[g]+=S,e[i]=a,e[a]=e[b]),i=a}return[e,i]}function K(e=0,n=Ee){n=Math.max(q,n);const r=new Int32Array(new SharedArrayBuffer(n<<2));return r[g]=q,r[b]=e,r}function Z(e,n=0){const r=e[g];n=Math.max(n,Math.ceil(r*fe));const l=new Int32Array(new SharedArrayBuffer(n<<2));for(let i=0;ie[o].length&&(e[o]=Z(e[o],t+H),i.add(o)),e[o][g]+=H,e[o][s]=t,e[o][t]=w,e[o][t+O]=R;else{const E=e[o][t];o!==E&&(t=e[o][t+O]),a.push([E,t,w,R])}}s+=p,I+=p}}a.splice(0,f)}while(a.length>0);return Array.from(i)}function ge(e,n,r,l,i="",a){const f=new Array(n.length+1);f[0]=[r,N+y,0];let u=0,o=!1;do{let[s,c,I]=f[u];if(I>=F){--u;continue}f[u][1]+=p,++f[u][2];let _=e[s][c];if(_===h)continue;const T=e[s][_];s!==T&&(_=e[s][_+O],s=T),n[u]=I+k,f[++u]=[s,_+y,0];const R=e[s][_+m];R!==h&&(o&&l.write(i),o=!0,a(l,n,u,R))}while(u>=0)}function ye(e){const n=new J.Worker(e);return n.on("error",r=>{throw r}),n.on("messageerror",r=>{throw r}),n.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${n.threadId} exited with code ${r}`)}),n}function G(e,n){return new Promise(r=>{e.once("message",r),e.postMessage(n)})}async function Ne(e,n,r,l=""){r=v(r,ae,se);const i=await ce(e,r,x,oe);r=i.length;const a=new SharedArrayBuffer(U*r+1<<4),f=new Int16Array(a),u=new Int16Array(a,2),o=new Uint32Array(a,4),s=new Float64Array(a,8),c=new Array(r),I=new Array(r);for(let t=0;t{c[E.id]=E.trie});for(let t=_.length-1;t>0;--t){const E=t-1>>1,d=t;_[E]=_[E].then(()=>_[d]).then(()=>G(I[E],{type:"merge",a:E,b:d,counts:o,maxes:u,mins:f,sums:s,tries:c})).then(M=>{for(const A of M.ids)c[A]=M.tries[A]})}for(let t=0;tI[t].terminate());await Promise.all(_);const T=L.createWriteStream(l,{fd:l.length<1?1:void 0,flags:"a",highWaterMark:re}),R=Buffer.allocUnsafe(Q);T.write("{"),ge(c,R,0,T,", ",w),T.end(`} -`);function w(t,E,d,M){const A=Math.round(s[M<<1]/o[M<<2]);t.write(E.toString("utf8",0,d)),t.write("="),t.write((f[M<<3]/10).toFixed(1)),t.write("/"),t.write((A/10).toFixed(1)),t.write("/"),t.write((u[M<<3]/10).toFixed(1))}}const Y=11*C,$=111*C;function De(e,n,r){return e[n]===ie?(++n,n+4>r?Y-10*e[n]-e[n+2]:$-100*e[n]-10*e[n+1]-e[n+3]):n+4>r?10*e[n]+e[n+2]-Y:100*e[n]+10*e[n+1]+e[n+3]-$}async function pe({end:e,filePath:n,id:r,start:l,counts:i,maxes:a,mins:f,sums:u}){if(l>=e)return{id:r,trie:K(r,0)};let o=K(r),s=r*U+1;const c=Buffer.allocUnsafe(x),I=L.createReadStream(n,{start:l,end:e-1,highWaterMark:ue(e-l)});let _=0,T;for await(const t of I){const E=t.length;for(let d=0;d=E?a[t]:E,++i[t>>1],u[t>>2]+=E}return{id:r,trie:o}}function Oe({a:e,b:n,tries:r,counts:l,maxes:i,mins:a,sums:f}){function u(o,s){o<<=3,s<<=3,a[o]=Math.min(a[o],a[s]),i[o]=Math.max(i[o],i[s]),l[o>>1]+=l[s>>1],f[o>>2]+=f[s>>2]}return{ids:me(r,e,n,u),tries:r}}if(D.isMainThread){const e=j.fileURLToPath(typeof document>"u"?require("url").pathToFileURL(__filename).href:X&&X.src||new URL("index.cjs",document.baseURI).href);Ne(process.argv[2],e,V.availableParallelism())}else D.parentPort.addListener("message",async e=>{if(e.type==="process")D.parentPort.postMessage(await pe(e));else if(e.type==="merge")D.parentPort.postMessage(Oe(e));else throw new Error("Unknown message type")}); +"use strict";var j=require("node:os"),z=require("node:url"),D=require("node:worker_threads"),X=require("node:fs"),J=require("fs/promises"),Q=require("worker_threads"),U=typeof document<"u"?document.currentScript:null;const x=1e4,ee=100,P=107,te=16384,re=1048576,ne=1048576,ae=152e-6,oe=16384,se=1,ie=512,_e=45,W=10,C=59,k=48,v=32,ce=216;function F(e,r,t){return e>r?e<=t?e:t:r}async function ue(e,r,t,l=0){const _=await J.open(e);try{const a=(await _.stat()).size,f=Math.max(l,Math.floor(a/r)),u=Buffer.allocUnsafe(t),n=[];let o=0;for(let c=f;c=0&&Ee.length&&(e=G(e,a+H)),e[y]+=H,e[_]=a,e[a]=e[q]),_=a}return[e,_]}function Z(e=0,r=fe){r=Math.max(K,r);const t=new Int32Array(new SharedArrayBuffer(r<<2));return t[y]=K,t[q]=e,t}function G(e,r=0){const t=e[y];r=Math.max(r,Math.ceil(t*le));const l=new Int32Array(new SharedArrayBuffer(r<<2));for(let _=0;_e[n].length&&(e[n]=G(e[n],s+L),_.add(n)),e[n][y]+=L,e[n][o]=s,e[n][s]=A,e[n][s+S]=R;else{const i=e[n][s];n!==i&&(s=e[n][s+S]),a.push([i,s,A,R])}}o+=O,I+=O}}a.splice(0,f)}while(a.length>0);return Array.from(_)}function ge(e,r,t,l,_="",a){const f=new Array(r.length+1);f[0]=[t,N+g,0];let u=0,n=!1;do{let[o,c,I]=f[u];if(I>=B){--u;continue}f[u][1]+=O,++f[u][2];let E=e[o][c];if(E===w)continue;const T=e[o][E];o!==T&&(E=e[o][E+S],o=T),r[u]=I+v,f[++u]=[o,E+g,0];const R=e[o][E+m];R!==w&&(n&&l.write(_),n=!0,a(l,r,u,R))}while(u>=0)}function Ne(e){const r=new Q.Worker(e);return r.on("error",t=>{throw t}),r.on("messageerror",t=>{throw t}),r.on("exit",t=>{if(t>1||t<0)throw new Error(`Worker ${r.threadId} exited with code ${t}`)}),r}function Y(e,r){return new Promise(t=>{e.once("message",t),e.postMessage(r)})}async function pe(e,r,t,l=""){t=F(t,se,ie);const _=await ue(e,t,P,oe);t=_.length;const a=new SharedArrayBuffer(x*t+1<<4),f=new Int16Array(a),u=new Int16Array(a,2),n=new Uint32Array(a,4),o=new Float64Array(a,8),c=new Array(t),I=[],E=new Array(t),T=new Array(t);for(let i=0;i{const M=d.id;for(c[d.id]=d.trie;I.length>0;){const h=await Y(E[M],{type:"merge",a:M,b:I.pop(),counts:n,maxes:u,mins:f,sums:o,tries:c});for(const p of h.ids)c[p]=h.tries[p]}return I.push(M),E[M].terminate()});await Promise.all(T);const R=X.createWriteStream(l,{fd:l.length<1?1:void 0,flags:"a",highWaterMark:ne}),A=Buffer.allocUnsafe(ee);R.write("{"),ge(c,A,I[0],R,", ",s),R.end(`} +`);function s(i,d,M,h){const p=Math.round(o[h<<1]/n[h<<2]);i.write(d.toString("utf8",0,M)),i.write("="),i.write((f[h<<3]/10).toFixed(1)),i.write("/"),i.write((p/10).toFixed(1)),i.write("/"),i.write((u[h<<3]/10).toFixed(1))}}const $=11*k,V=111*k;function De(e,r,t){return e[r]===_e?(++r,r+4>t?$-10*e[r]-e[r+2]:V-100*e[r]-10*e[r+1]-e[r+3]):r+4>t?10*e[r]+e[r+2]-$:100*e[r]+10*e[r+1]+e[r+3]-V}async function Oe({end:e,filePath:r,id:t,start:l,counts:_,maxes:a,mins:f,sums:u}){if(l>=e)return{id:t,trie:Z(t,0)};let n=Z(t),o=t*x+1;const c=Buffer.allocUnsafe(P),I=X.createReadStream(r,{start:l,end:e-1,highWaterMark:Ee(e-l)});let E=0,T;for await(const s of I){const i=s.length;for(let d=0;d=i?a[s]:i,++_[s>>1],u[s>>2]+=i}return{id:t,trie:n}}function Se({a:e,b:r,tries:t,counts:l,maxes:_,mins:a,sums:f}){function u(n,o){n<<=3,o<<=3,a[n]=Math.min(a[n],a[o]),_[n]=Math.max(_[n],_[o]),l[n>>1]+=l[o>>1],f[n>>2]+=f[o>>2]}return{ids:ye(t,e,r,u),tries:t}}if(D.isMainThread){const e=z.fileURLToPath(typeof document>"u"?require("url").pathToFileURL(__filename).href:U&&U.src||new URL("index.cjs",document.baseURI).href);pe(process.argv[2],e,j.availableParallelism())}else D.parentPort.addListener("message",async e=>{if(e.type==="process")D.parentPort.postMessage(await Oe(e));else if(e.type==="merge")D.parentPort.postMessage(Se(e));else throw new Error("Unknown message type")}); //# sourceMappingURL=index.cjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs.map b/src/main/nodejs/havelessbemore/dist/index.cjs.map index 3cda020..580c792 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.cjs.map @@ -1 +1 @@ -{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/constants/utf8.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/utils/parse.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n *\n * @remarks\n *\n * Changing this value affects the `count` and\n * `sum` values used for calculating a station's\n * average temperature.\n *\n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n *\n * @remarks\n *\n * Changing this value affects the `min`, `max` and `sum` values\n * used for calculating a station's min, max and avg\n * temperatures, respectively.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n *\n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n *\n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n *\n * @remarks\n *\n * This limit should be sufficient for most use cases.\n * However, feel free to adjust up or down as needed.\n *\n * There is not much basis for the current value.\n * Development was done with at most 8 workers and\n * a reasonable input file, with memory never exceeding\n * 20 MiB total across all workers.\n *\n * In theory, the challenge constraints allow for input\n * files that would require each worker using upwards of\n * 800 MiB; 10K stations with completely unique 100 byte names,\n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = trie[index /*+ TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index /*+ TRIE_PTR_IDX_IDX*/] = child;\n // Initialize node\n trie[child /* + TRIE_NODE_ID_IDX*/] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr /* + TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child /* + TRIE_NODE_ID_IDX*/];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi /* + TRIE_PTR_IDX_IDX*/];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri /*+ TRIE_NODE_ID_IDX*/];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai /*+ TRIE_PTR_IDX_IDX*/];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai /*+ TRIE_PTR_IDX_IDX*/] = li;\n // Initialize redirect\n tries[at][li /* + TRIE_XPTR_ID_IDX*/] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li /* + TRIE_NODE_ID_IDX*/];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr /* + TRIE_PTR_IDX_IDX*/];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI /* + TRIE_NODE_ID_IDX*/];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { CHAR_MINUS, CHAR_ZERO } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CHAR_MINUS);\n b[min + ~sign] = CHAR_ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CHAR_MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { parseDouble } from \"./utils/parse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CHAR_NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 4;\n if (buffer[semI - 2] === CHAR_SEMICOLON) {\n semI -= 2;\n } else if (buffer[semI - 1] === CHAR_SEMICOLON) {\n semI -= 1;\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Request } from \"./types/request\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === \"process\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","MIN_WORKERS","MAX_WORKERS","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","CHAR_ZERO_11","CHAR_ZERO_111","parseDouble","stations","createReadStream","bufI","leaf","chunk","N","semI","tempV","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","_documentCurrentScript","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/constants/utf8.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/utils/parse.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n *\n * @remarks\n *\n * Changing this value affects the `count` and\n * `sum` values used for calculating a station's\n * average temperature.\n *\n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n *\n * @remarks\n *\n * Changing this value affects the `min`, `max` and `sum` values\n * used for calculating a station's min, max and avg\n * temperatures, respectively.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n *\n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n *\n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n *\n * @remarks\n *\n * This limit should be sufficient for most use cases.\n * However, feel free to adjust up or down as needed.\n *\n * There is not much basis for the current value.\n * Development was done with at most 8 workers and\n * a reasonable input file, with memory never exceeding\n * 20 MiB total across all workers.\n *\n * In theory, the challenge constraints allow for input\n * files that would require each worker using upwards of\n * 800 MiB; 10K stations with completely unique 100 byte names,\n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = trie[index /*+ TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index /*+ TRIE_PTR_IDX_IDX*/] = child;\n // Initialize node\n trie[child /* + TRIE_NODE_ID_IDX*/] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr /* + TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child /* + TRIE_NODE_ID_IDX*/];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi /* + TRIE_PTR_IDX_IDX*/];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri /*+ TRIE_NODE_ID_IDX*/];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai /*+ TRIE_PTR_IDX_IDX*/];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai /*+ TRIE_PTR_IDX_IDX*/] = li;\n // Initialize redirect\n tries[at][li /* + TRIE_XPTR_ID_IDX*/] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li /* + TRIE_NODE_ID_IDX*/];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr /* + TRIE_PTR_IDX_IDX*/];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI /* + TRIE_NODE_ID_IDX*/];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\nimport { Worker } from \"node:worker_threads\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const workers: Worker[] = new Array(maxWorkers);\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n workers[i] = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(workers[i], {\n type: \"process\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add the worker's trie\n const a = res.id;\n tries[res.id] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(workers[a], {\n type: \"merge\",\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return workers[a].terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { CHAR_MINUS, CHAR_ZERO } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CHAR_MINUS);\n b[min + ~sign] = CHAR_ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CHAR_MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { parseDouble } from \"./utils/parse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CHAR_NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 4;\n if (buffer[semI - 2] === CHAR_SEMICOLON) {\n semI -= 2;\n } else if (buffer[semI - 1] === CHAR_SEMICOLON) {\n semI -= 1;\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Request } from \"./types/request\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === \"process\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","MIN_WORKERS","MAX_WORKERS","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","unmerged","workers","tasks","a","out","createWriteStream","printStation","name","nameLen","vi","avg","CHAR_ZERO_11","CHAR_ZERO_111","parseDouble","b","stations","createReadStream","bufI","leaf","chunk","N","semI","tempV","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","_documentCurrentScript","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index 79ce98c..206319f 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -24,6 +24,6 @@ * SOFTWARE. */ -import{availableParallelism as $}from"node:os";import{fileURLToPath as V}from"node:url";import{isMainThread as z,parentPort as H}from"node:worker_threads";import{createWriteStream as j,createReadStream as q}from"node:fs";import{open as J}from"fs/promises";import{Worker as Q}from"worker_threads";const X=1e4,tt=100,L=107,et=16384,rt=1048576,nt=1048576,ot=152e-6,at=16384,st=1,it=512,_t=45,x=10,U=59,W=48,P=32,ct=216;function C(t,n,r){return t>n?t<=r?t:r:n}async function Et(t,n,r,I=0){const i=await J(t);try{const a=(await i.stat()).size,l=Math.max(I,Math.floor(a/n)),E=Buffer.allocUnsafe(r),o=[];let s=0;for(let c=l;c=0&&_t.length&&(t=b(t,a+p)),t[g]+=p,t[i]=a,t[a]=t[B]),i=a}return[t,i]}function Z(t=0,n=lt){n=Math.max(K,n);const r=new Int32Array(new SharedArrayBuffer(n<<2));return r[g]=K,r[B]=t,r}function b(t,n=0){const r=t[g];n=Math.max(n,Math.ceil(r*It));const I=new Int32Array(new SharedArrayBuffer(n<<2));for(let i=0;it[o].length&&(t[o]=b(t[o],e+S),i.add(o)),t[o][g]+=S,t[o][s]=e,t[o][e]=w,t[o][e+O]=R;else{const f=t[o][e];o!==f&&(e=t[o][e+O]),a.push([f,e,w,R])}}s+=D,u+=D}}a.splice(0,l)}while(a.length>0);return Array.from(i)}function Nt(t,n,r,I,i="",a){const l=new Array(n.length+1);l[0]=[r,y+N,0];let E=0,o=!1;do{let[s,c,u]=l[E];if(u>=F){--E;continue}l[E][1]+=D,++l[E][2];let _=t[s][c];if(_===m)continue;const T=t[s][_];s!==T&&(_=t[s][_+O],s=T),n[E]=u+P,l[++E]=[s,_+N,0];const R=t[s][_+d];R!==m&&(o&&I.write(i),o=!0,a(I,n,E,R))}while(E>=0)}function yt(t){const n=new Q(t);return n.on("error",r=>{throw r}),n.on("messageerror",r=>{throw r}),n.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${n.threadId} exited with code ${r}`)}),n}function G(t,n){return new Promise(r=>{t.once("message",r),t.postMessage(n)})}async function Dt(t,n,r,I=""){r=C(r,st,it);const i=await Et(t,r,L,at);r=i.length;const a=new SharedArrayBuffer(X*r+1<<4),l=new Int16Array(a),E=new Int16Array(a,2),o=new Uint32Array(a,4),s=new Float64Array(a,8),c=new Array(r),u=new Array(r);for(let e=0;e{c[f.id]=f.trie});for(let e=_.length-1;e>0;--e){const f=e-1>>1,h=e;_[f]=_[f].then(()=>_[h]).then(()=>G(u[f],{type:"merge",a:f,b:h,counts:o,maxes:E,mins:l,sums:s,tries:c})).then(M=>{for(const A of M.ids)c[A]=M.tries[A]})}for(let e=0;eu[e].terminate());await Promise.all(_);const T=j(I,{fd:I.length<1?1:void 0,flags:"a",highWaterMark:nt}),R=Buffer.allocUnsafe(tt);T.write("{"),Nt(c,R,0,T,", ",w),T.end(`} -`);function w(e,f,h,M){const A=Math.round(s[M<<1]/o[M<<2]);e.write(f.toString("utf8",0,h)),e.write("="),e.write((l[M<<3]/10).toFixed(1)),e.write("/"),e.write((A/10).toFixed(1)),e.write("/"),e.write((E[M<<3]/10).toFixed(1))}}const v=11*W,Y=111*W;function Ot(t,n,r){return t[n]===_t?(++n,n+4>r?v-10*t[n]-t[n+2]:Y-100*t[n]-10*t[n+1]-t[n+3]):n+4>r?10*t[n]+t[n+2]-v:100*t[n]+10*t[n+1]+t[n+3]-Y}async function pt({end:t,filePath:n,id:r,start:I,counts:i,maxes:a,mins:l,sums:E}){if(I>=t)return{id:r,trie:Z(r,0)};let o=Z(r),s=r*X+1;const c=Buffer.allocUnsafe(L),u=q(n,{start:I,end:t-1,highWaterMark:ft(t-I)});let _=0,T;for await(const e of u){const f=e.length;for(let h=0;h=f?a[e]:f,++i[e>>1],E[e>>2]+=f}return{id:r,trie:o}}function Ht({a:t,b:n,tries:r,counts:I,maxes:i,mins:a,sums:l}){function E(o,s){o<<=3,s<<=3,a[o]=Math.min(a[o],a[s]),i[o]=Math.max(i[o],i[s]),I[o>>1]+=I[s>>1],l[o>>2]+=l[s>>2]}return{ids:gt(r,t,n,E),tries:r}}if(z){const t=V(import.meta.url);Dt(process.argv[2],t,$())}else H.addListener("message",async t=>{if(t.type==="process")H.postMessage(await pt(t));else if(t.type==="merge")H.postMessage(Ht(t));else throw new Error("Unknown message type")}); +import{availableParallelism as V}from"node:os";import{fileURLToPath as z}from"node:url";import{isMainThread as j,parentPort as H}from"node:worker_threads";import{createWriteStream as q,createReadStream as J}from"node:fs";import{open as Q}from"fs/promises";import{Worker as tt}from"worker_threads";const L=1e4,et=100,x=107,rt=16384,nt=1048576,ot=1048576,at=152e-6,st=16384,it=1,_t=512,ct=45,U=10,W=59,P=48,C=32,Et=216;function F(t,r,e){return t>r?t<=e?t:e:r}async function ft(t,r,e,I=0){const _=await Q(t);try{const o=(await _.stat()).size,u=Math.max(I,Math.floor(o/r)),E=Buffer.allocUnsafe(e),n=[];let a=0;for(let c=u;c=0&&ft.length&&(t=G(t,o+S)),t[g]+=S,t[_]=o,t[o]=t[K]),_=o}return[t,_]}function b(t=0,r=It){r=Math.max(Z,r);const e=new Int32Array(new SharedArrayBuffer(r<<2));return e[g]=Z,e[K]=t,e}function G(t,r=0){const e=t[g];r=Math.max(r,Math.ceil(e*lt));const I=new Int32Array(new SharedArrayBuffer(r<<2));for(let _=0;_t[n].length&&(t[n]=G(t[n],s+X),_.add(n)),t[n][g]+=X,t[n][a]=s,t[n][s]=A,t[n][s+O]=R;else{const i=t[n][s];n!==i&&(s=t[n][s+O]),o.push([i,s,A,R])}}a+=D,l+=D}}o.splice(0,u)}while(o.length>0);return Array.from(_)}function yt(t,r,e,I,_="",o){const u=new Array(r.length+1);u[0]=[e,y+N,0];let E=0,n=!1;do{let[a,c,l]=u[E];if(l>=k){--E;continue}u[E][1]+=D,++u[E][2];let f=t[a][c];if(f===w)continue;const T=t[a][f];a!==T&&(f=t[a][f+O],a=T),r[E]=l+C,u[++E]=[a,f+N,0];const R=t[a][f+d];R!==w&&(n&&I.write(_),n=!0,o(I,r,E,R))}while(E>=0)}function pt(t){const r=new tt(t);return r.on("error",e=>{throw e}),r.on("messageerror",e=>{throw e}),r.on("exit",e=>{if(e>1||e<0)throw new Error(`Worker ${r.threadId} exited with code ${e}`)}),r}function v(t,r){return new Promise(e=>{t.once("message",e),t.postMessage(r)})}async function Dt(t,r,e,I=""){e=F(e,it,_t);const _=await ft(t,e,x,st);e=_.length;const o=new SharedArrayBuffer(L*e+1<<4),u=new Int16Array(o),E=new Int16Array(o,2),n=new Uint32Array(o,4),a=new Float64Array(o,8),c=new Array(e),l=[],f=new Array(e),T=new Array(e);for(let i=0;i{const M=m.id;for(c[m.id]=m.trie;l.length>0;){const h=await v(f[M],{type:"merge",a:M,b:l.pop(),counts:n,maxes:E,mins:u,sums:a,tries:c});for(const p of h.ids)c[p]=h.tries[p]}return l.push(M),f[M].terminate()});await Promise.all(T);const R=q(I,{fd:I.length<1?1:void 0,flags:"a",highWaterMark:ot}),A=Buffer.allocUnsafe(et);R.write("{"),yt(c,A,l[0],R,", ",s),R.end(`} +`);function s(i,m,M,h){const p=Math.round(a[h<<1]/n[h<<2]);i.write(m.toString("utf8",0,M)),i.write("="),i.write((u[h<<3]/10).toFixed(1)),i.write("/"),i.write((p/10).toFixed(1)),i.write("/"),i.write((E[h<<3]/10).toFixed(1))}}const Y=11*P,$=111*P;function Ot(t,r,e){return t[r]===ct?(++r,r+4>e?Y-10*t[r]-t[r+2]:$-100*t[r]-10*t[r+1]-t[r+3]):r+4>e?10*t[r]+t[r+2]-Y:100*t[r]+10*t[r+1]+t[r+3]-$}async function St({end:t,filePath:r,id:e,start:I,counts:_,maxes:o,mins:u,sums:E}){if(I>=t)return{id:e,trie:b(e,0)};let n=b(e),a=e*L+1;const c=Buffer.allocUnsafe(x),l=J(r,{start:I,end:t-1,highWaterMark:ut(t-I)});let f=0,T;for await(const s of l){const i=s.length;for(let m=0;m=i?o[s]:i,++_[s>>1],E[s>>2]+=i}return{id:e,trie:n}}function Ht({a:t,b:r,tries:e,counts:I,maxes:_,mins:o,sums:u}){function E(n,a){n<<=3,a<<=3,o[n]=Math.min(o[n],o[a]),_[n]=Math.max(_[n],_[a]),I[n>>1]+=I[a>>1],u[n>>2]+=u[a>>2]}return{ids:Nt(e,t,r,E),tries:e}}if(j){const t=z(import.meta.url);Dt(process.argv[2],t,V())}else H.addListener("message",async t=>{if(t.type==="process")H.postMessage(await St(t));else if(t.type==="merge")H.postMessage(Ht(t));else throw new Error("Unknown message type")}); //# sourceMappingURL=index.mjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index 2ad0349..6dc3bf5 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1 +1 @@ -{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/constants/utf8.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/utils/parse.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n *\n * @remarks\n *\n * Changing this value affects the `count` and\n * `sum` values used for calculating a station's\n * average temperature.\n *\n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n *\n * @remarks\n *\n * Changing this value affects the `min`, `max` and `sum` values\n * used for calculating a station's min, max and avg\n * temperatures, respectively.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n *\n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n *\n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n *\n * @remarks\n *\n * This limit should be sufficient for most use cases.\n * However, feel free to adjust up or down as needed.\n *\n * There is not much basis for the current value.\n * Development was done with at most 8 workers and\n * a reasonable input file, with memory never exceeding\n * 20 MiB total across all workers.\n *\n * In theory, the challenge constraints allow for input\n * files that would require each worker using upwards of\n * 800 MiB; 10K stations with completely unique 100 byte names,\n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = trie[index /*+ TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index /*+ TRIE_PTR_IDX_IDX*/] = child;\n // Initialize node\n trie[child /* + TRIE_NODE_ID_IDX*/] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr /* + TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child /* + TRIE_NODE_ID_IDX*/];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi /* + TRIE_PTR_IDX_IDX*/];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri /*+ TRIE_NODE_ID_IDX*/];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai /*+ TRIE_PTR_IDX_IDX*/];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai /*+ TRIE_PTR_IDX_IDX*/] = li;\n // Initialize redirect\n tries[at][li /* + TRIE_XPTR_ID_IDX*/] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li /* + TRIE_NODE_ID_IDX*/];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr /* + TRIE_PTR_IDX_IDX*/];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI /* + TRIE_NODE_ID_IDX*/];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\nimport { Worker } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Create workers\n const workers = new Array(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n workers[i] = createWorker(workerPath);\n }\n\n // Process each chunk\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = exec(workers[i], {\n type: \"process\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then((res) => {\n tries[res.id] = res.trie;\n });\n }\n\n // Merge tries\n for (let i = tasks.length - 1; i > 0; --i) {\n const a = (i - 1) >> 1;\n const b = i;\n tasks[a] = tasks[a]\n .then(() => tasks[b])\n .then(() =>\n exec(workers[a], {\n type: \"merge\",\n a,\n b,\n counts,\n maxes,\n mins,\n sums,\n tries,\n }),\n )\n .then((res) => {\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n });\n }\n\n // Terminate workers\n for (let i = 0; i < maxWorkers; ++i) {\n tasks[i] = tasks[i].then(() => workers[i].terminate());\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, 0, out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { CHAR_MINUS, CHAR_ZERO } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CHAR_MINUS);\n b[min + ~sign] = CHAR_ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CHAR_MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { parseDouble } from \"./utils/parse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CHAR_NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 4;\n if (buffer[semI - 2] === CHAR_SEMICOLON) {\n semI -= 2;\n } else if (buffer[semI - 1] === CHAR_SEMICOLON) {\n semI -= 1;\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Request } from \"./types/request\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === \"process\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","MIN_WORKERS","MAX_WORKERS","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","workers","tasks","a","b","out","createWriteStream","printStation","name","nameLen","vi","avg","CHAR_ZERO_11","CHAR_ZERO_111","parseDouble","stations","createReadStream","bufI","leaf","chunk","N","semI","tempV","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/constants/utf8.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/utils/parse.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n *\n * @remarks\n *\n * Changing this value affects the `count` and\n * `sum` values used for calculating a station's\n * average temperature.\n *\n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n *\n * @remarks\n *\n * Changing this value affects the `min`, `max` and `sum` values\n * used for calculating a station's min, max and avg\n * temperatures, respectively.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n *\n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n *\n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n *\n * @remarks\n *\n * This limit should be sufficient for most use cases.\n * However, feel free to adjust up or down as needed.\n *\n * There is not much basis for the current value.\n * Development was done with at most 8 workers and\n * a reasonable input file, with memory never exceeding\n * 20 MiB total across all workers.\n *\n * In theory, the challenge constraints allow for input\n * files that would require each worker using upwards of\n * 800 MiB; 10K stations with completely unique 100 byte names,\n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = trie[index /*+ TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index /*+ TRIE_PTR_IDX_IDX*/] = child;\n // Initialize node\n trie[child /* + TRIE_NODE_ID_IDX*/] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr /* + TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child /* + TRIE_NODE_ID_IDX*/];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi /* + TRIE_PTR_IDX_IDX*/];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri /*+ TRIE_NODE_ID_IDX*/];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai /*+ TRIE_PTR_IDX_IDX*/];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai /*+ TRIE_PTR_IDX_IDX*/] = li;\n // Initialize redirect\n tries[at][li /* + TRIE_XPTR_ID_IDX*/] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li /* + TRIE_NODE_ID_IDX*/];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr /* + TRIE_PTR_IDX_IDX*/];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI /* + TRIE_NODE_ID_IDX*/];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\nimport { Worker } from \"node:worker_threads\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const workers: Worker[] = new Array(maxWorkers);\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n workers[i] = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(workers[i], {\n type: \"process\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add the worker's trie\n const a = res.id;\n tries[res.id] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(workers[a], {\n type: \"merge\",\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return workers[a].terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { CHAR_MINUS, CHAR_ZERO } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CHAR_MINUS);\n b[min + ~sign] = CHAR_ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CHAR_MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { parseDouble } from \"./utils/parse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CHAR_NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 4;\n if (buffer[semI - 2] === CHAR_SEMICOLON) {\n semI -= 2;\n } else if (buffer[semI - 1] === CHAR_SEMICOLON) {\n semI -= 1;\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Request } from \"./types/request\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === \"process\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","MIN_WORKERS","MAX_WORKERS","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","unmerged","workers","tasks","a","out","createWriteStream","printStation","name","nameLen","vi","avg","CHAR_ZERO_11","CHAR_ZERO_111","parseDouble","b","stations","createReadStream","bufI","leaf","chunk","N","semI","tempV","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;yRAaa,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAaAA,EAAe,CAafC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAuB,CA6BvBC,CAAAA,CAAAA,CAAAA,CAAAA,CAAgB,CCjEhBC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAsB,CAKtBC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAsB,CAKtBC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAsB,CAMtBC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAwB,CAKxBC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAiB,CCrBjBC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAc,EAwBdC,CAAc,CAAA,CAAA,CAAA,CAAA,CAAA,CCtBdC,CAAa,CAAA,CAAA,CAAA,CAAA,CAKbC,CAAe,CAAA,CAAA,CAAA,CAUfC,CAAiB,CAAA,CAAA,CAAA,CAKjBC,CAAY,CAAA,CAAA,CAAA,CAWZC,CAAgB,CAAA,CAAA,CAAA,CAYhBC,CAAiB,CAAA,CAAA,CAAA,CAAA,CAAA,EC9BdC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAMC,EAAeC,CAAaC,CAAAA,CAAAA,CAAqB,CACrE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAOF,CAAQC,CAAAA,CAAAA,CAAOD,CAASE,CAAAA,CAAAA,CAAAA,CAAMF,CAAQE,CAAAA,CAAAA,CAAOD,CACtD,EAoBsBE,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACpBC,CACAC,CAAAA,CAAAA,CACAC,CACAC,CAAAA,CAAAA,CAAU,CACmB,CAAA,CAE7B,CAAMC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAO,CAAMC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAKL,CAAQ,CAAA,CAChC,CAAI,CAAA,CAAA,CAEF,CAAMM,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAQ,CAAMF,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAK,MAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAE3BG,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAIJ,CAAAA,CAAAA,CAAAA,CAAAA,CAAS,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMG,CAAOL,CAAAA,CAAM,CAAC,CAAA,CAEvDO,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAYN,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAa,EACzCO,CAA6B,CAAA,EAEnC,CAAA,CAAA,CAAA,CAAA,CAAIC,CAAQ,CAAA,CAAA,CACZ,CAASC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAMJ,CAAWI,CAAAA,CAAAA,CAAML,CAAMK,CAAAA,CAAAA,CAAAA,CAAOJ,CAAW,CAAA,CAEtD,CAAMK,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAM,MAAMR,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAKI,CAAQ,CAAA,CAAA,CAAGN,CAAeS,CAAAA,CAAG,CAEnDE,CAAAA,CAAAA,CAAUL,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQlB,CAAY,CAAA,CAEvCuB,CAAW,CAAA,CAAA,CAAA,CAAA,CAAKA,CAAUD,CAAAA,CAAAA,CAAI,CAEhCD,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAOE,CAAU,CAAA,CAAA,CAEjBJ,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAACC,CAAAA,CAAOC,CAAG,CAAC,CAExBD,CAAAA,CAAAA,CAAQC,CAEZ,CAAA,CAEA,CAAID,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAQJ,GACVG,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAACC,CAAAA,CAAOJ,CAAI,CAAC,CAGpBG,CAAAA,CACT,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAEA,CAAML,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAK,OACb,CACF,CASO,SAASU,CAAiBR,CAAAA,CAAAA,CAAAA,CAAsB,CAErD,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAA,CAAQrB,CAAAA,CAAAA,CAAAA,CAAAA,CAERqB,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAKA,CAAAA,CAAAA,CAAAA,CAAAA,CAAI,CAAC,CAAA,CAEjCA,CAAO,CAAA,CAAA,CAAA,CAAKA,EAELX,CAAMW,CAAAA,CAAAA,CAAMxB,CAAqBC,CAAAA,CAAAA,CAAAA,CAAmB,CAC7D,CC3Fa,CAAAgC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAoB,CAKpBC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAqB,CAWrBC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAmB,CAEnBC,CAAAA,CAAAA,CAAeD,CAQfE,CAAAA,CAAAA,CAAAA,CAAAA,CAAmB,EAGnBC,CAAoB,CAAA,CAAA,CACpBC,CAAoB,CAAA,CAAA,CAAA,CAEpBC,CAAgBH,CAAAA,CAAAA,CAAAA,CAAmBE,CAKnCE,CAAAA,CAAAA,CAAAA,CAAAA,CAAmB,CACnBC,CAAAA,CAAAA,CAAAA,CAAmB,CAGnBC,CAAAA,CAAAA,CAAsB,CACtBC,CAAAA,CAAAA,CAAAA,CAAsB,CAGtBC,CAAAA,CAAAA,CAAyB,EACzBC,CAAyBlC,CAAAA,CAAAA,CAAAA,CACzBmC,CAAyBX,CAAAA,CAAAA,CAAeU,CAExCE,CAAAA,CAAAA,CACXN,CAAmBE,CAAAA,CAAAA,CAAAA,CAAAA,CAAsBG,CAO9BE,CAAAA,CAAAA,CAAY,CAGZC,CAAAA,CAAAA,CAAgB,CAChBC,CAAAA,CAAAA,CAAAA,CAAgB,CAGhBC,CAAAA,CAAAA,CAAgB,EAChBC,CAAgBL,CAAAA,CAAAA,CAAAA,CAGhBM,CAAcF,CAAAA,CAAAA,CAAgBX,CAE9Bc,CAAAA,CAAAA,CAAAA,CAAWJ,CAAgBE,CAAAA,CAAAA,CAAAA,CAAAA,CC3DxB,CAAAG,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACdC,CACAC,CAAAA,CAAAA,CACA3C,CACAC,CAAAA,CAAAA,CACsB,CACtB,CAAA,CAAA,CAAA,CAAI2C,EAAQP,CACZ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAOrC,CAAMC,CAAAA,CAAAA,CAAAA,CAAK,CAChB2C,CAAAA,CAAAA,CACEd,CAA8Ca,CAAAA,CAAAA,CAAAA,CAAI3C,CAAK,CAAA,CAAA,CAAA,CAAIJ,CAC7D,CAAA,CAAA,CAAA,CAAA,CAAA,CAAIiD,CAAQH,CAAAA,CAAAA,CAAKE,CAA4B,CAAA,CACzCC,CAAUX,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAEZW,CAAQH,CAAAA,CAAAA,CAAKP,CAAa,CAAA,CACtBU,CAAQZ,CAAAA,CAAAA,CAAgBS,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAC/BA,CAAOI,CAAAA,CAAAA,CAAKJ,CAAMG,CAAAA,CAAAA,CAAQZ,CAAa,CAAA,CAAA,CAEzCS,EAAKP,CAAa,CAAA,CAAA,CAAKF,CAEvBS,CAAAA,CAAAA,CAAKE,CAA4B,CAAA,CAAIC,CAErCH,CAAAA,CAAAA,CAAKG,CAA6B,CAAA,CAAIH,CAAKH,CAAAA,CAAW,CAExDK,CAAAA,CAAAA,CAAAA,CAAQC,CACV,CAEA,MAAO,CAACH,CAAAA,CAAME,CAAK,CACrB,CA8BgB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAG,CAAWC,CAAAA,CAAAA,CAAK,CAAGvC,CAAAA,CAAAA,CAAOS,CAA+B,CAAA,CAAA,CACvET,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAI+B,CAAAA,CAAAA,CAAAA,CAAAA,CAAU/B,CAAI,CAC9B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMiC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAI,CAAW,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAkBjC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAQ,CAAC,CAAC,CAC5D,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAiC,CAAKP,CAAAA,CAAa,CAAIK,CAAAA,CAAAA,CACtBE,EAAKH,CAAW,CAAA,CAAIS,CACbN,CAAAA,CACT,UAEgBI,CAAKJ,CAAAA,CAAAA,CAAkBpC,CAAU,CAAA,CAAA,CAAe,CAC9D,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM2C,CAASP,CAAAA,CAAAA,CAAKP,CAAa,CAAA,CACjC7B,EAAU,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAIA,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAK2C,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAS9B,CAAkB,CAAA,CAAC,CAClE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM+B,CAAO,CAAA,CAAA,CAAA,CAAA,CAAI,CAAW,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAkB5C,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAW,CAAC,CAAC,CAAA,CAC/D,CAAS6C,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAI,CAAGA,CAAAA,CAAAA,CAAIF,CAAQ,CAAA,CAAA,CAAEE,CAC5BD,CAAAA,CAAAA,CAAKC,CAAC,CAAA,CAAIT,CAAKS,CAAAA,CAAC,CAElB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAOD,CACT,UAEgBE,CACdC,CAAAA,CAAAA,CAAAA,CACAC,CACAC,CAAAA,CAAAA,CACAC,CACU,CAAA,CACV,CAAMC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAQ,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACZC,CAA4C,CAAA,CAChD,CAACJ,CAAAA,CAAIjB,CAAekB,CAAAA,CAAAA,CAAIlB,CAAa,CACvC,CAEA,CAAA,CAAA,CAAG,CACD,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMsB,CAAID,CAAAA,CAAAA,CAAM,CAChB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAASE,CAAI,CAAA,CAAA,CAAGA,CAAID,CAAAA,CAAAA,CAAG,EAAEC,CAAG,CAAA,CAE1B,CAAI,CAAA,CAAA,CAACN,CAAIO,CAAAA,CAAAA,CAAIN,CAAIO,CAAAA,CAAE,CAAIJ,CAAAA,CAAAA,CAAME,CAAC,CAAA,CAG9B,CAAMG,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAMV,CAAME,CAAAA,CAAE,EAAEO,CAAKlC,CAAAA,CAAmB,CAC9C,CAAA,CAAA,CAAA,CAAImC,CAAQ7B,CAAAA,CAAAA,CAAAA,CAAAA,CAAW,CAErB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM8B,CAAMX,CAAAA,CAAAA,CAAMC,CAAE,CAAA,CAAEO,CAAKjC,CAAAA,CAAmB,CAC1CoC,CAAAA,CAAAA,CAAAA,CAAAA,CAAQ9B,EACVsB,CAAQQ,CAAAA,CAAAA,CAAKD,CAAG,CAAA,CAEhBV,CAAMC,CAAAA,CAAE,CAAEO,CAAAA,CAAAA,CAAKjC,CAAmB,CAAA,CAAImC,CAE1C,CAGAF,CAAM/B,CAAAA,CAAAA,CAAAA,CACNgC,CAAMhC,CAAAA,CAAAA,CAAAA,CAGN,MAAMmC,CAAKH,CAAAA,CAAAA,CAAK9B,CAChB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO8B,CAAKG,CAAAA,CAAAA,CAAAA,CAAI,CAEd,CAAA,CAAA,CAAA,CAAIC,CAAKb,CAAAA,CAAAA,CAAME,CAAE,CAAA,CAAEO,CAA0B,CAAA,CAC7C,CAAII,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAOhC,EAAW,CAEpB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMiC,CAAKd,CAAAA,CAAAA,CAAME,CAAE,CAAA,CAAEW,CAAyB,CAAA,CAC1CX,CAAOY,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACTD,CAAKb,CAAAA,CAAAA,CAAME,CAAE,CAAA,CAAEW,CAAK3C,CAAAA,CAAiB,GAIvC,CAAI6C,CAAAA,CAAAA,CAAAA,CAAAA,CAAKf,CAAMC,CAAAA,CAAE,CAAEO,CAAAA,CAAyB,CAC5C,CAAA,CAAA,CAAA,CAAIO,CAAOlC,CAAAA,CAAAA,CAAAA,CAAAA,CAETkC,CAAKf,CAAAA,CAAAA,CAAMC,CAAE,CAAA,CAAEnB,CAAa,CAAA,CACxBiC,EAAK3C,CAAgB4B,CAAAA,CAAAA,CAAMC,CAAE,CAAA,CAAE,CACjCD,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAMC,CAAE,CAAA,CAAIR,CAAKO,CAAAA,CAAAA,CAAMC,CAAE,CAAA,CAAGc,CAAK3C,CAAAA,CAAa,CAC9CgC,CAAAA,CAAAA,CAAM,CAAIH,CAAAA,CAAAA,CAAAA,CAAE,CAEdD,CAAAA,CAAAA,CAAAA,CAAMC,CAAE,CAAA,CAAEnB,CAAa,CAAA,CAAA,CAAKV,CAE5B4B,CAAAA,CAAAA,CAAMC,CAAE,CAAA,CAAEO,CAAyB,CAAA,CAAIO,CAEvCf,CAAAA,CAAAA,CAAMC,CAAE,CAAEc,CAAAA,CAA0B,CAAID,CAAAA,CAAAA,CACxCd,CAAMC,CAAAA,CAAE,CAAEc,CAAAA,CAAAA,CAAK7C,CAAiB,CAAA,CAAI2C,CAC/B,CAAA,CAAA,CAAA,CAAA,CAAA,CAEL,CAAMG,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAKhB,CAAMC,CAAAA,CAAE,EAAEc,CAA0B,CAAA,CAC3Cd,CAAOe,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACTD,CAAKf,CAAAA,CAAAA,CAAMC,CAAE,CAAA,CAAEc,CAAK7C,CAAAA,CAAiB,CAGvCmC,CAAAA,CAAAA,CAAAA,CAAM,CAAK,CAAA,CAAA,CAAA,CAAA,CAACW,CAAID,CAAAA,CAAAA,CAAID,EAAID,CAAE,CAAC,CAC7B,CACF,CAGAL,CAAAA,CAAAA,CAAMxC,CACNyC,CAAAA,CAAAA,CAAAA,CAAMzC,CACR,CACF,CACAqC,CAAAA,CAAM,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAGC,CAAC,CACnB,OAASD,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CACxB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAKD,CAAK,CACzB,CAEO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAASa,CACdjB,CAAAA,CAAAA,CAAAA,CACAV,CACA4B,CAAAA,CAAAA,CACAC,CACAC,CAAAA,CAAAA,CAAY,GACZC,CAMM,CAAA,CACN,CAAMC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAQ,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAgChC,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAC,CAAA,CAChEgC,CAAM,CAAA,CAAC,CAAI,CAAA,CAACJ,CAAWlC,CAAAA,CAAAA,CAAgBP,EAAwB,CAAC,CAAA,CAEhE,CAAI8C,CAAAA,CAAAA,CAAAA,CAAAA,CAAM,CACNC,CAAAA,CAAAA,CAAO,CACX,CAAA,CAAA,CAAA,CAAG,CAED,CAAA,CAAA,CAAI,CAACC,CAAAA,CAAOC,CAAUC,CAAAA,CAAQ,CAAIL,CAAAA,CAAAA,CAAMC,CAAG,CAG3C,CAAA,CAAA,CAAA,CAAII,CAAYjD,CAAAA,CAAAA,CAAAA,CAAwB,CACtC,CAAA,CAAE6C,CACF,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACF,CAGAD,CAAAA,CAAMC,CAAG,CAAA,CAAE,CAAC,CAAA,CAAA,CAAKvD,CACjB,CAAA,CAAA,CAAEsD,CAAMC,CAAAA,CAAG,CAAE,CAAA,CAAC,CAGd,CAAA,CAAA,CAAA,CAAA,CAAIK,CAAS5B,CAAAA,CAAAA,CAAMyB,CAAK,CAAA,CAAEC,CAAgC,CAAA,CAC1D,CAAIE,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAW/C,CACb,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAIF,MAAMgD,CAAa7B,CAAAA,CAAAA,CAAMyB,CAAK,CAAA,CAAEG,CAA8B,CAAA,CAC1DH,CAAUI,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACZD,CAAS5B,CAAAA,CAAAA,CAAMyB,CAAK,CAAA,CAAEG,CAAS1D,CAAAA,CAAiB,CAChDuD,CAAAA,CAAAA,CAAQI,GAIVvC,CAAIiC,CAAAA,CAAG,CAAII,CAAAA,CAAAA,CAAWpF,CACtB+E,CAAAA,CAAAA,CAAM,CAAEC,CAAAA,CAAG,CAAI,CAAA,CAACE,CAAOG,CAAAA,CAAAA,CAASnD,CAAwB,CAAA,CAAC,CAGzD,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMqD,EAAa9B,CAAMyB,CAAAA,CAAK,CAAEG,CAAAA,CAAAA,CAASrD,CAAmB,CAAA,CACxDuD,CAAejD,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAEb2C,CACFL,CAAAA,CAAAA,CAAAA,CAAO,CAAMC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAS,CAExBI,CAAAA,CAAAA,CAAO,CACPH,CAAAA,CAAAA,CAAAA,CAAWF,EAAQ7B,CAAKiC,CAAAA,CAAAA,CAAKO,CAAU,CAAA,CAE3C,CAASP,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAO,CAClB,CAAA,CCpOgB,CAAAQ,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAaC,CAA4B,CAAA,CACvD,CAAMC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAS,CAAIC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAOF,CAAU,CACpC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAC,CAAO,CAAA,CAAA,CAAA,CAAG,CAAUE,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAQ,CAC1B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMA,CACR,CAAC,CACDF,CAAAA,CAAAA,CAAO,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAiBE,CAAQ,CAAA,CAAA,CACjC,MAAMA,CACR,CAAC,CACDF,CAAAA,CAAAA,CAAO,CAAG,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAASG,CAAS,CAAA,CAAA,CAC1B,CAAIA,CAAAA,CAAAA,CAAAA,CAAO,CAAKA,CAAAA,CAAAA,CAAAA,CAAO,CACrB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,UAAUH,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAqBG,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAI,CAAE,CAAA,CAExE,CAAC,CAAA,CACMH,CACT,CAUgB,CAAAI,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAeJ,CAAgBK,CAAAA,CAAAA,CAAwB,CACrE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAcC,CAAY,CAAA,CAAA,CACnCN,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAWM,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAO,CAC9BN,CAAAA,CAAAA,CAAO,CAAYK,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAG,CACxB,CAAC,CACH,CCnBsB,eAAAE,CACpB1F,CAAAA,CAAAA,CAAAA,CACAkF,CACAS,CAAAA,CAAAA,CACAC,CAAU,CAAA,CAAA,CAAA,CACK,CAEfD,CAAAA,CAAahG,CAAMgG,CAAAA,CAAAA,CAAYxG,CAAaC,CAAAA,CAAAA,CAAAA,CAAW,CAGvD,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMqB,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMV,GACnBC,CACA2F,CAAAA,CAAAA,CACA9G,CACAK,CAAAA,CAAAA,CACF,CAGAyG,CAAAA,CAAAA,CAAalF,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAGpB,CAAMoF,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAS,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAmBlH,CAAegH,CAAAA,CAAAA,CAAa,CAAM,CAAA,CAAA,CAAC,EACnEG,CAAO,CAAA,CAAA,CAAA,CAAA,CAAI,CAAWD,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAM,CAC5BE,CAAAA,CAAAA,CAAQ,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAWF,CAAQ,CAAA,CAAC,CAChCG,CAAAA,CAAAA,CAAS,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAYH,CAAQ,CAAA,CAAC,EAClCI,CAAO,CAAA,CAAA,CAAA,CAAA,CAAI,CAAaJ,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAQ,CAAC,CAAA,CACjC3C,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAI,CAAkByC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAU,CAGxCO,CAAAA,CAAAA,CAAqB,CAAC,CAAA,CACtBC,CAAoB,CAAA,CAAA,CAAA,CAAA,CAAI,MAAMR,CAAU,CAAA,CACxCS,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAI,CAAwBT,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAU,CACpD,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS3C,CAAI,CAAA,CAAA,CAAGA,CAAI2C,CAAAA,CAAAA,CAAY,CAAE3C,CAAAA,CAAAA,CAEhCmD,CAAQnD,CAAAA,CAAC,EAAIiC,CAAaC,CAAAA,CAAAA,CAAU,CAEpCkB,CAAAA,CAAAA,CAAMpD,CAAC,CAAA,CAAIuC,CAAsCY,CAAAA,CAAAA,CAAQnD,CAAC,CAAA,CAAG,CAC3D,CAAA,CAAA,CAAA,CAAA,CAAM,CACN,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAgD,CACA,CAAA,CAAA,CAAA,CAAA,CAAKvF,EAAOuC,CAAC,CAAA,CAAE,CAAC,CAAA,CAChB,CAAAhD,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACA,CAAIgD,CAAAA,CAAAA,CAAAA,CACJ,CAAA+C,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACA,CAAAD,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACA,CAAOrF,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAOuC,CAAC,CAAA,CAAE,CAAC,CAAA,CAClB,CAAAiD,CAAAA,CAAAA,CAAAA,CAAAA,CACF,CAAC,CAAA,CAAE,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAOrF,CAAQ,CAAA,CAAA,CAErB,CAAMyF,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAIzF,CAAI,CAAA,CAAA,CAAA,CAGd,CAFAsC,CAAAA,CAAAA,CAAAA,CAAAA,CAAMtC,EAAI,CAAE,CAAA,CAAA,CAAIA,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAEbsF,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS,CAAG,CAAA,CAAA,CAC1B,CAAMtF,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAM,CAAM2E,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAkCY,CAAQE,CAAAA,CAAC,CAAG,CAAA,CAC9D,KAAM,CACN,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAA,CACA,CAAA,CAAA,CAAGH,CAAS,CAAA,CAAA,CAAA,CAAA,CAAI,CAChB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAF,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAD,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAD,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAG,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA/C,CACF,CAAC,CAAA,CACD,CAAWL,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAMjC,CAAI,CAAA,CAAA,CAAA,CAAA,CACnBsC,CAAML,CAAAA,CAAE,CAAIjC,CAAAA,CAAAA,CAAI,CAAMiC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAE,CAE5B,CACA,CAAAqD,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAS,KAAKG,CAAC,CAAA,CAERF,CAAQE,CAAAA,CAAC,CAAE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,EACpB,CAAC,CAIH,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAID,CAAK,CAAA,CAGvB,CAAME,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAMC,EAAkBX,CAAS,CAAA,CACrC,CAAIA,CAAAA,CAAAA,CAAAA,CAAQ,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAC7B,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACP,CAAe5G,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACjB,CAAC,CAAA,CACKwB,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,YAAY5B,CAAoB,CAAA,CAAA,CACtD0H,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAG,CAAA,CAAA,CAAA,CACbnC,CAAMjB,CAAAA,CAAAA,CAAAA,CAAO1C,CAAQ0F,CAAAA,CAAAA,CAAS,CAAC,CAAA,CAAGI,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAME,CAAY,CAAA,CACzDF,EAAI,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA;AAAA,CAAK,CAEb,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAASE,CACPnC,CAAAA,CAAAA,CACAoC,CACAC,CAAAA,CAAAA,CACAC,CACM,CAAA,CACN,CAAMC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAM,CAAK,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMX,CAAKU,CAAAA,CAAAA,CAAAA,CAAM,CAAC,CAAA,CAAIX,CAAOW,CAAAA,CAAAA,CAAAA,CAAM,CAAC,CAAC,CACtDtC,CAAAA,CAAAA,CAAO,CAAMoC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAK,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAGC,CAAAA,CAAO,CAAC,CAAA,CAC9CrC,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM,CAAG,CAAA,CAAA,CAAA,CAChBA,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAOyB,CAAKa,CAAAA,CAAAA,CAAAA,CAAM,CAAC,CAAA,CAAI,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAC,CAAC,CAC5CtC,CAAAA,CAAAA,CAAO,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAChBA,CAAAA,CAAAA,CAAO,CAAOuC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAM,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAC,CAAC,CAClCvC,CAAAA,CAAAA,CAAO,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAG,CAChBA,CAAAA,CAAAA,CAAO,CAAO0B,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAMY,CAAM,CAAA,CAAA,CAAC,CAAI,CAAA,CAAA,CAAA,CAAA,CAAI,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAC,CAAC,CAC/C,CACF,ECtHaE,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAe,CAAKrH,CAAAA,CAAAA,CAAAA,CACpBsH,CAAgB,CAAA,CAAA,CAAA,CAAA,CAAMtH,CAO5B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAASuH,CAAYC,CAAAA,CAAAA,CAAAA,CAAWnH,CAAaC,CAAAA,CAAAA,CAAqB,CACvE,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAIkH,CAAEnH,CAAAA,CAAG,CAAMR,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CACb,CAAEQ,CAAAA,CAAAA,CACKA,CAAM,CAAA,CAAA,CAAIC,CACb+G,CAAAA,CAAAA,CAAe,CAAKG,CAAAA,CAAAA,CAAAA,CAAEnH,CAAG,CAAA,CAAImH,CAAEnH,CAAAA,CAAAA,CAAM,CAAC,CAAA,CACtCiH,CAAgB,CAAA,CAAA,CAAA,CAAA,CAAME,CAAEnH,CAAAA,CAAG,CAAI,CAAA,CAAA,CAAA,CAAKmH,CAAEnH,CAAAA,CAAAA,CAAM,CAAC,CAAA,CAAImH,CAAEnH,CAAAA,CAAAA,CAAM,CAAC,CAAA,CAAA,CAEzDA,CAAM,CAAA,CAAA,CAAIC,CACb,CAAA,CAAA,CAAA,CAAKkH,EAAEnH,CAAG,CAAA,CAAImH,CAAEnH,CAAAA,CAAAA,CAAM,CAAC,CAAA,CAAIgH,CAC3B,CAAA,CAAA,CAAA,CAAA,CAAMG,CAAEnH,CAAAA,CAAG,CAAI,CAAA,CAAA,CAAA,CAAKmH,CAAEnH,CAAAA,CAAAA,CAAM,CAAC,CAAA,CAAImH,CAAEnH,CAAAA,CAAAA,CAAM,CAAC,CAAA,CAAIiH,CACpD,ECLsBpB,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAI,CACxB,CAAA,CAAA,CAAA,CAAA/E,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAX,CACA,CAAA,CAAA,CAAA,CAAA6C,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAnC,CAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAsF,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAD,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAD,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAG,CACF,CAAA,CAA6C,CAE3C,CAAA,CAAA,CAAIvF,CAASC,CAAAA,CAAAA,CAAAA,CACX,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CAAAkC,CAAAA,CAAAA,CAAAA,CAAI,CAAMD,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAWC,CAAI,CAAA,CAAC,CAAE,CAAA,CAIvC,CAAIN,CAAAA,CAAAA,CAAAA,CAAAA,CAAOK,CAAWC,CAAAA,CAAE,CACpBoE,CAAAA,CAAAA,CAAWpE,CAAKlE,CAAAA,CAAAA,CAAe,CACnC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAM6B,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAY3B,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAa,CAGzCwF,CAAAA,CAAAA,CAAS6C,CAAiBlH,CAAAA,CAAAA,CAAU,CACxC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAU,CACA,CAAA,CAAA,CAAA,CAAA,CAAKC,CAAM,CAAA,CAAA,CACX,CAAeG,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAiBH,CAAMD,CAAAA,CAAK,CAC7C,CAAC,CAGD,CAAA,CAAA,CAAA,CAAA,CAAIyG,CAAO,CAAA,CAAA,CACPC,CACJ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAiBC,CAAShD,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAQ,CAEhC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAMiD,CAAID,CAAAA,CAAAA,CAAM,CAChB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAASrE,CAAI,CAAA,CAAA,CAAGA,CAAIsE,CAAAA,CAAAA,CAAG,CAAEtE,CAAAA,CAAAA,CAAG,CAE1B,CAAA,CAAA,CAAIqE,CAAMrE,CAAAA,CAAC,CAAM1D,CAAAA,CAAAA,CAAAA,CAAAA,CAAc,CAC7BkB,CAAAA,CAAO2G,CAAM,CAAA,CAAA,CAAA,CAAIE,CAAMrE,CAAAA,CAAC,CACxB,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACF,CAGA,CAAA,CAAA,CAAA,CAAIuE,CAAOJ,CAAAA,CAAAA,CAAO,CACd3G,CAAAA,CAAAA,CAAO+G,CAAO,CAAA,CAAC,IAAMhI,CACvBgI,CAAAA,CAAAA,CAAAA,CAAQ,CACC/G,CAAAA,CAAAA,CAAO+G,CAAO,CAAA,CAAC,CAAMhI,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAC9BgI,CAAQ,CAAA,CAAA,CAAA,CAAA,CAIV,CAAMC,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAQT,CAAYvG,CAAAA,CAAAA,CAAAA,CAAQ+G,CAAO,CAAA,CAAA,CAAGJ,CAAI,CAAA,CAChDA,CAAO,CAAA,CAAA,CAGP,CAAC5E,CAAAA,CAAM6E,CAAI,CAAA,CAAI9E,CAAIC,CAAAA,CAAAA,CAAAA,CAAM/B,CAAQ,CAAA,CAAA,CAAG+G,CAAI,CAAA,CAGpChF,CAAK6E,CAAAA,CAAAA,CAAO3F,CAAmB,CAAA,CAAA,CAAA,CAAMM,CAEvC0F,CAAAA,CAAAA,CAAclF,CAAK6E,CAAAA,CAAAA,CAAO3F,CAAmB,CAAA,CAAG+F,CAAK,CAAA,CAAA,CAGrDjF,CAAK6E,CAAAA,CAAAA,CAAO3F,CAAmB,CAAA,CAAIwF,CACnCS,CAAAA,CAAAA,CAAWT,CAAYO,CAAAA,CAAAA,CAAAA,CAAK,CAEhC,CAAA,CACF,CAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAASE,CAAWjF,CAAAA,CAAAA,CAAekF,CAAoB,CAAA,CACrD7B,CAAKrD,CAAAA,CAAAA,CAAAA,CAAS,CAAC,CAAA,CAAIkF,CACnB5B,CAAAA,CAAAA,CAAMtD,CAAS,CAAA,CAAA,CAAC,CAAIkF,CAAAA,CAAAA,CACpB3B,CAAOvD,CAAAA,CAAAA,CAAAA,CAAS,CAAC,CAAA,CAAI,CACrBwD,CAAAA,CAAAA,CAAKxD,CAAS,CAAA,CAAA,CAAC,CAAIkF,CAAAA,CACrB,CAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAASF,CAAchF,CAAAA,CAAAA,CAAekF,CAAoB,CAAA,CACxDlF,CAAU,CAAA,CAAA,CAAA,CAAA,CACVqD,CAAKrD,CAAAA,CAAK,CAAIqD,CAAAA,CAAAA,CAAKrD,CAAK,CAAA,CAAA,CAAKkF,CAAO7B,CAAAA,CAAAA,CAAKrD,CAAK,CAAA,CAAIkF,CAClD5B,CAAAA,CAAAA,CAAMtD,CAAK,CAAA,CAAIsD,CAAMtD,CAAAA,CAAK,CAAKkF,CAAAA,CAAAA,CAAAA,CAAO5B,CAAMtD,CAAAA,CAAK,CAAIkF,CAAAA,CAAAA,CACrD,CAAE3B,CAAAA,CAAAA,CAAOvD,CAAS,CAAA,CAAA,CAAC,CACnBwD,CAAAA,CAAAA,CAAKxD,CAAS,CAAA,CAAA,CAAC,CAAKkF,CAAAA,CAAAA,CACtB,CAEA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAO,CAAE,CAAA,CAAA,CAAA9E,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAN,CAAK,CACpB,UAEgBqF,GAAM,CACpB,CAAA,CAAAvB,CACA,CAAA,CAAA,CAAAW,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA9D,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA8C,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAD,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAD,CACA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAAG,CACF,CAAA,CAAgC,CAC9B,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAS4B,CAAcnE,CAAAA,CAAAA,CAAYC,CAAkB,CAAA,CACnDD,CAAO,CAAA,CAAA,CAAA,CAAA,CACPC,CAAO,CAAA,CAAA,CAAA,CAAA,CACPmC,CAAKpC,CAAAA,CAAE,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAIoC,CAAAA,CAAAA,CAAAA,CAAAA,CAAKpC,CAAE,CAAA,CAAGoC,CAAKnC,CAAAA,CAAE,CAAC,CAAA,CACtCoC,CAAMrC,CAAAA,CAAE,CAAI,CAAA,CAAA,CAAA,CAAA,CAAA,CAAK,CAAIqC,CAAAA,CAAAA,CAAAA,CAAAA,CAAMrC,CAAE,CAAA,CAAGqC,CAAMpC,CAAAA,CAAE,CAAC,CAAA,CACzCqC,CAAOtC,CAAAA,CAAAA,CAAAA,CAAM,CAAC,CAAA,CAAA,CAAKsC,CAAOrC,CAAAA,CAAAA,CAAAA,CAAM,CAAC,CAAA,CACjCsC,CAAKvC,CAAAA,CAAAA,CAAAA,CAAM,CAAC,CAAA,CAAA,CAAKuC,CAAKtC,CAAAA,CAAAA,CAAAA,CAAM,CAAC,CAC/B,CAEA,CAAO,CAAA,CAAA,CAAA,CAAA,CAAA,CAAE,CADGV,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAUC,CAAOmD,CAAAA,CAAAA,CAAGW,CAAGa,CAAAA,CAAa,CAClC,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA3E,CAAM,CACtB,CC9GA,CAAA,CAAA,CAAI4E,CAAc,CAAA,CAChB,CAAM5C,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAa6C,CAAc,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAY,CAAG,CAAA,CAAA,CAAA,CAChDC,CAAQ,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAQ,CAAK,CAAA,CAAA,CAAA,CAAA,CAAC,CAAG9C,CAAAA,CAAAA,CAAY+C,CAAqB,CAAA,CAAC,CAC7D,CAAA,CAAA,CAAA,CAAA,CAAA,CACEC,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAY,CAAW,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAOC,CAAiB,CAAA,CAAA,CACzD,CAAIA,CAAAA,CAAAA,CAAAA,CAAI,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACfD,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAY,CAAME,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAUD,CAAqB,CAAC,CACrDA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAAA,CAAI,CAAS,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CACtBD,CAAY,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAYN,CAAMO,CAAAA,CAAAA,CAAmB,CAAC,CAAA,CAAA,CAAA,CAAA,CAAA,CAE5C,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAI,CAAM,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAsB,CAE1C,CAAC,CAAA,CAAA;"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/src/main.ts b/src/main/nodejs/havelessbemore/src/main.ts index 91506a4..fa51bd5 100644 --- a/src/main/nodejs/havelessbemore/src/main.ts +++ b/src/main/nodejs/havelessbemore/src/main.ts @@ -1,5 +1,4 @@ import { WriteStream, createWriteStream } from "node:fs"; -import { Worker } from "node:worker_threads"; import type { MergeRequest } from "./types/mergeRequest"; import type { MergeResponse } from "./types/mergeResponse"; @@ -45,16 +44,14 @@ export async function run( const sums = new Float64Array(valBuf, 8); const tries = new Array(maxWorkers); - // Create workers - const workers = new Array(maxWorkers); - for (let i = 0; i < maxWorkers; ++i) { - workers[i] = createWorker(workerPath); - } - - // Process each chunk + // Run + const unmerged: number[] = []; const tasks = new Array>(maxWorkers); for (let i = 0; i < maxWorkers; ++i) { - tasks[i] = exec(workers[i], { + // Create the worker + const worker = createWorker(workerPath); + // Process the chunk + tasks[i] = exec(worker, { type: "process", counts, end: chunks[i][1], @@ -64,39 +61,30 @@ export async function run( mins, start: chunks[i][0], sums, - }).then((res) => { + }).then(async (res) => { + // Add the worker's trie + const a = res.id; tries[res.id] = res.trie; - }); - } - - // Merge tries - for (let i = tasks.length - 1; i > 0; --i) { - const a = (i - 1) >> 1; - const b = i; - tasks[a] = tasks[a] - .then(() => tasks[b]) - .then(() => - exec(workers[a], { + // Merge with other tries + while (unmerged.length > 0) { + const res = await exec(worker, { type: "merge", a, - b, + b: unmerged.pop()!, counts, maxes, mins, sums, tries, - }), - ) - .then((res) => { + }); for (const id of res.ids) { tries[id] = res.tries[id]; } - }); - } - - // Terminate workers - for (let i = 0; i < maxWorkers; ++i) { - tasks[i] = tasks[i].then(() => workers[i].terminate()); + } + unmerged.push(a); + // Stop worker + return worker.terminate(); + }); } // Wait for completion @@ -110,7 +98,7 @@ export async function run( }); const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN); out.write("{"); - print(tries, buffer, 0, out, ", ", printStation); + print(tries, buffer, unmerged[0], out, ", ", printStation); out.end("}\n"); function printStation( From e41c6ccd0ab8fdf0567a705dc8b20a9c00306b3f Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Fri, 24 May 2024 23:33:00 -0400 Subject: [PATCH 37/69] Format files --- src/main/nodejs/havelessbemore/dist/index.cjs | 4 ++-- src/main/nodejs/havelessbemore/dist/index.cjs.map | 2 +- src/main/nodejs/havelessbemore/dist/index.mjs | 4 ++-- src/main/nodejs/havelessbemore/dist/index.mjs.map | 2 +- src/main/nodejs/havelessbemore/src/main.ts | 3 ++- src/main/nodejs/havelessbemore/src/types/response.ts | 4 +--- 6 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs b/src/main/nodejs/havelessbemore/dist/index.cjs index 36eef50..1dac372 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs +++ b/src/main/nodejs/havelessbemore/dist/index.cjs @@ -24,6 +24,6 @@ * SOFTWARE. */ -"use strict";var j=require("node:os"),z=require("node:url"),D=require("node:worker_threads"),X=require("node:fs"),J=require("fs/promises"),Q=require("worker_threads"),U=typeof document<"u"?document.currentScript:null;const x=1e4,ee=100,P=107,te=16384,re=1048576,ne=1048576,ae=152e-6,oe=16384,se=1,ie=512,_e=45,W=10,C=59,k=48,v=32,ce=216;function F(e,r,t){return e>r?e<=t?e:t:r}async function ue(e,r,t,l=0){const _=await J.open(e);try{const a=(await _.stat()).size,f=Math.max(l,Math.floor(a/r)),u=Buffer.allocUnsafe(t),n=[];let o=0;for(let c=f;c=0&&Ee.length&&(e=G(e,a+H)),e[y]+=H,e[_]=a,e[a]=e[q]),_=a}return[e,_]}function Z(e=0,r=fe){r=Math.max(K,r);const t=new Int32Array(new SharedArrayBuffer(r<<2));return t[y]=K,t[q]=e,t}function G(e,r=0){const t=e[y];r=Math.max(r,Math.ceil(t*le));const l=new Int32Array(new SharedArrayBuffer(r<<2));for(let _=0;_e[n].length&&(e[n]=G(e[n],s+L),_.add(n)),e[n][y]+=L,e[n][o]=s,e[n][s]=A,e[n][s+S]=R;else{const i=e[n][s];n!==i&&(s=e[n][s+S]),a.push([i,s,A,R])}}o+=O,I+=O}}a.splice(0,f)}while(a.length>0);return Array.from(_)}function ge(e,r,t,l,_="",a){const f=new Array(r.length+1);f[0]=[t,N+g,0];let u=0,n=!1;do{let[o,c,I]=f[u];if(I>=B){--u;continue}f[u][1]+=O,++f[u][2];let E=e[o][c];if(E===w)continue;const T=e[o][E];o!==T&&(E=e[o][E+S],o=T),r[u]=I+v,f[++u]=[o,E+g,0];const R=e[o][E+m];R!==w&&(n&&l.write(_),n=!0,a(l,r,u,R))}while(u>=0)}function Ne(e){const r=new Q.Worker(e);return r.on("error",t=>{throw t}),r.on("messageerror",t=>{throw t}),r.on("exit",t=>{if(t>1||t<0)throw new Error(`Worker ${r.threadId} exited with code ${t}`)}),r}function Y(e,r){return new Promise(t=>{e.once("message",t),e.postMessage(r)})}async function pe(e,r,t,l=""){t=F(t,se,ie);const _=await ue(e,t,P,oe);t=_.length;const a=new SharedArrayBuffer(x*t+1<<4),f=new Int16Array(a),u=new Int16Array(a,2),n=new Uint32Array(a,4),o=new Float64Array(a,8),c=new Array(t),I=[],E=new Array(t),T=new Array(t);for(let i=0;i{const M=d.id;for(c[d.id]=d.trie;I.length>0;){const h=await Y(E[M],{type:"merge",a:M,b:I.pop(),counts:n,maxes:u,mins:f,sums:o,tries:c});for(const p of h.ids)c[p]=h.tries[p]}return I.push(M),E[M].terminate()});await Promise.all(T);const R=X.createWriteStream(l,{fd:l.length<1?1:void 0,flags:"a",highWaterMark:ne}),A=Buffer.allocUnsafe(ee);R.write("{"),ge(c,A,I[0],R,", ",s),R.end(`} -`);function s(i,d,M,h){const p=Math.round(o[h<<1]/n[h<<2]);i.write(d.toString("utf8",0,M)),i.write("="),i.write((f[h<<3]/10).toFixed(1)),i.write("/"),i.write((p/10).toFixed(1)),i.write("/"),i.write((u[h<<3]/10).toFixed(1))}}const $=11*k,V=111*k;function De(e,r,t){return e[r]===_e?(++r,r+4>t?$-10*e[r]-e[r+2]:V-100*e[r]-10*e[r+1]-e[r+3]):r+4>t?10*e[r]+e[r+2]-$:100*e[r]+10*e[r+1]+e[r+3]-V}async function Oe({end:e,filePath:r,id:t,start:l,counts:_,maxes:a,mins:f,sums:u}){if(l>=e)return{id:t,trie:Z(t,0)};let n=Z(t),o=t*x+1;const c=Buffer.allocUnsafe(P),I=X.createReadStream(r,{start:l,end:e-1,highWaterMark:Ee(e-l)});let E=0,T;for await(const s of I){const i=s.length;for(let d=0;d=i?a[s]:i,++_[s>>1],u[s>>2]+=i}return{id:t,trie:n}}function Se({a:e,b:r,tries:t,counts:l,maxes:_,mins:a,sums:f}){function u(n,o){n<<=3,o<<=3,a[n]=Math.min(a[n],a[o]),_[n]=Math.max(_[n],_[o]),l[n>>1]+=l[o>>1],f[n>>2]+=f[o>>2]}return{ids:ye(t,e,r,u),tries:t}}if(D.isMainThread){const e=z.fileURLToPath(typeof document>"u"?require("url").pathToFileURL(__filename).href:U&&U.src||new URL("index.cjs",document.baseURI).href);pe(process.argv[2],e,j.availableParallelism())}else D.parentPort.addListener("message",async e=>{if(e.type==="process")D.parentPort.postMessage(await Oe(e));else if(e.type==="merge")D.parentPort.postMessage(Se(e));else throw new Error("Unknown message type")}); +"use strict";var j=require("node:os"),z=require("node:url"),p=require("node:worker_threads"),X=require("node:fs"),J=require("fs/promises"),Q=require("worker_threads"),U=typeof document<"u"?document.currentScript:null;const x=1e4,ee=100,P=107,te=16384,re=1048576,ne=1048576,oe=152e-6,ae=16384,se=1,ie=512,_e=45,W=10,C=59,k=48,v=32,ce=216;function F(e,r,t){return e>r?e<=t?e:t:r}async function ue(e,r,t,f=0){const i=await J.open(e);try{const a=(await i.stat()).size,u=Math.max(f,Math.floor(a/r)),c=Buffer.allocUnsafe(t),o=[];let s=0;for(let _=u;_=0&&Ee.length&&(e=G(e,a+S)),e[g]+=S,e[i]=a,e[a]=e[q]),i=a}return[e,i]}function Z(e=0,r=fe){r=Math.max(K,r);const t=new Int32Array(new SharedArrayBuffer(r<<2));return t[g]=K,t[q]=e,t}function G(e,r=0){const t=e[g];r=Math.max(r,Math.ceil(t*le));const f=new Int32Array(new SharedArrayBuffer(r<<2));for(let i=0;ie[o].length&&(e[o]=G(e[o],n+H),i.add(o)),e[o][g]+=H,e[o][s]=n,e[o][n]=w,e[o][n+O]=R;else{const l=e[o][n];o!==l&&(n=e[o][n+O]),a.push([l,n,w,R])}}s+=D,I+=D}}a.splice(0,u)}while(a.length>0);return Array.from(i)}function ye(e,r,t,f,i="",a){const u=new Array(r.length+1);u[0]=[t,N+y,0];let c=0,o=!1;do{let[s,_,I]=u[c];if(I>=B){--c;continue}u[c][1]+=D,++u[c][2];let E=e[s][_];if(E===h)continue;const T=e[s][E];s!==T&&(E=e[s][E+O],s=T),r[c]=I+v,u[++c]=[s,E+y,0];const R=e[s][E+m];R!==h&&(o&&f.write(i),o=!0,a(f,r,c,R))}while(c>=0)}function Ne(e){const r=new Q.Worker(e);return r.on("error",t=>{throw t}),r.on("messageerror",t=>{throw t}),r.on("exit",t=>{if(t>1||t<0)throw new Error(`Worker ${r.threadId} exited with code ${t}`)}),r}function Y(e,r){return new Promise(t=>{e.once("message",t),e.postMessage(r)})}async function pe(e,r,t,f=""){t=F(t,se,ie);const i=await ue(e,t,P,ae);t=i.length;const a=new SharedArrayBuffer(x*t+1<<4),u=new Int16Array(a),c=new Int16Array(a,2),o=new Uint32Array(a,4),s=new Float64Array(a,8),_=new Array(t),I=[],E=new Array(t);for(let n=0;n{const M=d.id;for(_[d.id]=d.trie;I.length>0;){const A=await Y(l,{type:"merge",a:M,b:I.pop(),counts:o,maxes:c,mins:u,sums:s,tries:_});for(const L of A.ids)_[L]=A.tries[L]}return I.push(M),l.terminate()})}await Promise.all(E);const T=X.createWriteStream(f,{fd:f.length<1?1:void 0,flags:"a",highWaterMark:ne}),R=Buffer.allocUnsafe(ee);T.write("{"),ye(_,R,I[0],T,", ",w),T.end(`} +`);function w(n,l,d,M){const A=Math.round(s[M<<1]/o[M<<2]);n.write(l.toString("utf8",0,d)),n.write("="),n.write((u[M<<3]/10).toFixed(1)),n.write("/"),n.write((A/10).toFixed(1)),n.write("/"),n.write((c[M<<3]/10).toFixed(1))}}const $=11*k,V=111*k;function De(e,r,t){return e[r]===_e?(++r,r+4>t?$-10*e[r]-e[r+2]:V-100*e[r]-10*e[r+1]-e[r+3]):r+4>t?10*e[r]+e[r+2]-$:100*e[r]+10*e[r+1]+e[r+3]-V}async function Oe({end:e,filePath:r,id:t,start:f,counts:i,maxes:a,mins:u,sums:c}){if(f>=e)return{id:t,trie:Z(t,0)};let o=Z(t),s=t*x+1;const _=Buffer.allocUnsafe(P),I=X.createReadStream(r,{start:f,end:e-1,highWaterMark:Ee(e-f)});let E=0,T;for await(const n of I){const l=n.length;for(let d=0;d=l?a[n]:l,++i[n>>1],c[n>>2]+=l}return{id:t,trie:o}}function Se({a:e,b:r,tries:t,counts:f,maxes:i,mins:a,sums:u}){function c(o,s){o<<=3,s<<=3,a[o]=Math.min(a[o],a[s]),i[o]=Math.max(i[o],i[s]),f[o>>1]+=f[s>>1],u[o>>2]+=u[s>>2]}return{ids:ge(t,e,r,c),tries:t}}if(p.isMainThread){const e=z.fileURLToPath(typeof document>"u"?require("url").pathToFileURL(__filename).href:U&&U.src||new URL("index.cjs",document.baseURI).href);pe(process.argv[2],e,j.availableParallelism())}else p.parentPort.addListener("message",async e=>{if(e.type==="process")p.parentPort.postMessage(await Oe(e));else if(e.type==="merge")p.parentPort.postMessage(Se(e));else throw new Error("Unknown message type")}); //# sourceMappingURL=index.cjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs.map b/src/main/nodejs/havelessbemore/dist/index.cjs.map index 580c792..b07b308 100644 --- a/src/main/nodejs/havelessbemore/dist/index.cjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.cjs.map @@ -1 +1 @@ -{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/constants/utf8.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/utils/parse.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n *\n * @remarks\n *\n * Changing this value affects the `count` and\n * `sum` values used for calculating a station's\n * average temperature.\n *\n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n *\n * @remarks\n *\n * Changing this value affects the `min`, `max` and `sum` values\n * used for calculating a station's min, max and avg\n * temperatures, respectively.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n *\n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n *\n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n *\n * @remarks\n *\n * This limit should be sufficient for most use cases.\n * However, feel free to adjust up or down as needed.\n *\n * There is not much basis for the current value.\n * Development was done with at most 8 workers and\n * a reasonable input file, with memory never exceeding\n * 20 MiB total across all workers.\n *\n * In theory, the challenge constraints allow for input\n * files that would require each worker using upwards of\n * 800 MiB; 10K stations with completely unique 100 byte names,\n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = trie[index /*+ TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index /*+ TRIE_PTR_IDX_IDX*/] = child;\n // Initialize node\n trie[child /* + TRIE_NODE_ID_IDX*/] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr /* + TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child /* + TRIE_NODE_ID_IDX*/];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi /* + TRIE_PTR_IDX_IDX*/];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri /*+ TRIE_NODE_ID_IDX*/];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai /*+ TRIE_PTR_IDX_IDX*/];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai /*+ TRIE_PTR_IDX_IDX*/] = li;\n // Initialize redirect\n tries[at][li /* + TRIE_XPTR_ID_IDX*/] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li /* + TRIE_NODE_ID_IDX*/];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr /* + TRIE_PTR_IDX_IDX*/];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI /* + TRIE_NODE_ID_IDX*/];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\nimport { Worker } from \"node:worker_threads\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const workers: Worker[] = new Array(maxWorkers);\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n workers[i] = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(workers[i], {\n type: \"process\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add the worker's trie\n const a = res.id;\n tries[res.id] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(workers[a], {\n type: \"merge\",\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return workers[a].terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { CHAR_MINUS, CHAR_ZERO } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CHAR_MINUS);\n b[min + ~sign] = CHAR_ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CHAR_MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { parseDouble } from \"./utils/parse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CHAR_NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 4;\n if (buffer[semI - 2] === CHAR_SEMICOLON) {\n semI -= 2;\n } else if (buffer[semI - 1] === CHAR_SEMICOLON) {\n semI -= 1;\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Request } from \"./types/request\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === \"process\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","MIN_WORKERS","MAX_WORKERS","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","unmerged","workers","tasks","a","out","createWriteStream","printStation","name","nameLen","vi","avg","CHAR_ZERO_11","CHAR_ZERO_111","parseDouble","b","stations","createReadStream","bufI","leaf","chunk","N","semI","tempV","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","_documentCurrentScript","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/constants/utf8.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/utils/parse.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n *\n * @remarks\n *\n * Changing this value affects the `count` and\n * `sum` values used for calculating a station's\n * average temperature.\n *\n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n *\n * @remarks\n *\n * Changing this value affects the `min`, `max` and `sum` values\n * used for calculating a station's min, max and avg\n * temperatures, respectively.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n *\n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n *\n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n *\n * @remarks\n *\n * This limit should be sufficient for most use cases.\n * However, feel free to adjust up or down as needed.\n *\n * There is not much basis for the current value.\n * Development was done with at most 8 workers and\n * a reasonable input file, with memory never exceeding\n * 20 MiB total across all workers.\n *\n * In theory, the challenge constraints allow for input\n * files that would require each worker using upwards of\n * 800 MiB; 10K stations with completely unique 100 byte names,\n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = trie[index /*+ TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index /*+ TRIE_PTR_IDX_IDX*/] = child;\n // Initialize node\n trie[child /* + TRIE_NODE_ID_IDX*/] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr /* + TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child /* + TRIE_NODE_ID_IDX*/];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi /* + TRIE_PTR_IDX_IDX*/];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri /*+ TRIE_NODE_ID_IDX*/];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai /*+ TRIE_PTR_IDX_IDX*/];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai /*+ TRIE_PTR_IDX_IDX*/] = li;\n // Initialize redirect\n tries[at][li /* + TRIE_XPTR_ID_IDX*/] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li /* + TRIE_NODE_ID_IDX*/];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr /* + TRIE_PTR_IDX_IDX*/];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI /* + TRIE_NODE_ID_IDX*/];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: \"process\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[res.id] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: \"merge\",\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { CHAR_MINUS, CHAR_ZERO } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CHAR_MINUS);\n b[min + ~sign] = CHAR_ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CHAR_MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { parseDouble } from \"./utils/parse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CHAR_NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 4;\n if (buffer[semI - 2] === CHAR_SEMICOLON) {\n semI -= 2;\n } else if (buffer[semI - 1] === CHAR_SEMICOLON) {\n semI -= 1;\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Request } from \"./types/request\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === \"process\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","MIN_WORKERS","MAX_WORKERS","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","unmerged","tasks","a","out","createWriteStream","printStation","name","nameLen","vi","avg","CHAR_ZERO_11","CHAR_ZERO_111","parseDouble","b","stations","createReadStream","bufI","leaf","chunk","N","semI","tempV","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","_documentCurrentScript","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index 206319f..022b3ce 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -24,6 +24,6 @@ * SOFTWARE. */ -import{availableParallelism as V}from"node:os";import{fileURLToPath as z}from"node:url";import{isMainThread as j,parentPort as H}from"node:worker_threads";import{createWriteStream as q,createReadStream as J}from"node:fs";import{open as Q}from"fs/promises";import{Worker as tt}from"worker_threads";const L=1e4,et=100,x=107,rt=16384,nt=1048576,ot=1048576,at=152e-6,st=16384,it=1,_t=512,ct=45,U=10,W=59,P=48,C=32,Et=216;function F(t,r,e){return t>r?t<=e?t:e:r}async function ft(t,r,e,I=0){const _=await Q(t);try{const o=(await _.stat()).size,u=Math.max(I,Math.floor(o/r)),E=Buffer.allocUnsafe(e),n=[];let a=0;for(let c=u;c=0&&ft.length&&(t=G(t,o+S)),t[g]+=S,t[_]=o,t[o]=t[K]),_=o}return[t,_]}function b(t=0,r=It){r=Math.max(Z,r);const e=new Int32Array(new SharedArrayBuffer(r<<2));return e[g]=Z,e[K]=t,e}function G(t,r=0){const e=t[g];r=Math.max(r,Math.ceil(e*lt));const I=new Int32Array(new SharedArrayBuffer(r<<2));for(let _=0;_t[n].length&&(t[n]=G(t[n],s+X),_.add(n)),t[n][g]+=X,t[n][a]=s,t[n][s]=A,t[n][s+O]=R;else{const i=t[n][s];n!==i&&(s=t[n][s+O]),o.push([i,s,A,R])}}a+=D,l+=D}}o.splice(0,u)}while(o.length>0);return Array.from(_)}function yt(t,r,e,I,_="",o){const u=new Array(r.length+1);u[0]=[e,y+N,0];let E=0,n=!1;do{let[a,c,l]=u[E];if(l>=k){--E;continue}u[E][1]+=D,++u[E][2];let f=t[a][c];if(f===w)continue;const T=t[a][f];a!==T&&(f=t[a][f+O],a=T),r[E]=l+C,u[++E]=[a,f+N,0];const R=t[a][f+d];R!==w&&(n&&I.write(_),n=!0,o(I,r,E,R))}while(E>=0)}function pt(t){const r=new tt(t);return r.on("error",e=>{throw e}),r.on("messageerror",e=>{throw e}),r.on("exit",e=>{if(e>1||e<0)throw new Error(`Worker ${r.threadId} exited with code ${e}`)}),r}function v(t,r){return new Promise(e=>{t.once("message",e),t.postMessage(r)})}async function Dt(t,r,e,I=""){e=F(e,it,_t);const _=await ft(t,e,x,st);e=_.length;const o=new SharedArrayBuffer(L*e+1<<4),u=new Int16Array(o),E=new Int16Array(o,2),n=new Uint32Array(o,4),a=new Float64Array(o,8),c=new Array(e),l=[],f=new Array(e),T=new Array(e);for(let i=0;i{const M=m.id;for(c[m.id]=m.trie;l.length>0;){const h=await v(f[M],{type:"merge",a:M,b:l.pop(),counts:n,maxes:E,mins:u,sums:a,tries:c});for(const p of h.ids)c[p]=h.tries[p]}return l.push(M),f[M].terminate()});await Promise.all(T);const R=q(I,{fd:I.length<1?1:void 0,flags:"a",highWaterMark:ot}),A=Buffer.allocUnsafe(et);R.write("{"),yt(c,A,l[0],R,", ",s),R.end(`} -`);function s(i,m,M,h){const p=Math.round(a[h<<1]/n[h<<2]);i.write(m.toString("utf8",0,M)),i.write("="),i.write((u[h<<3]/10).toFixed(1)),i.write("/"),i.write((p/10).toFixed(1)),i.write("/"),i.write((E[h<<3]/10).toFixed(1))}}const Y=11*P,$=111*P;function Ot(t,r,e){return t[r]===ct?(++r,r+4>e?Y-10*t[r]-t[r+2]:$-100*t[r]-10*t[r+1]-t[r+3]):r+4>e?10*t[r]+t[r+2]-Y:100*t[r]+10*t[r+1]+t[r+3]-$}async function St({end:t,filePath:r,id:e,start:I,counts:_,maxes:o,mins:u,sums:E}){if(I>=t)return{id:e,trie:b(e,0)};let n=b(e),a=e*L+1;const c=Buffer.allocUnsafe(x),l=J(r,{start:I,end:t-1,highWaterMark:ut(t-I)});let f=0,T;for await(const s of l){const i=s.length;for(let m=0;m=i?o[s]:i,++_[s>>1],E[s>>2]+=i}return{id:e,trie:n}}function Ht({a:t,b:r,tries:e,counts:I,maxes:_,mins:o,sums:u}){function E(n,a){n<<=3,a<<=3,o[n]=Math.min(o[n],o[a]),_[n]=Math.max(_[n],_[a]),I[n>>1]+=I[a>>1],u[n>>2]+=u[a>>2]}return{ids:Nt(e,t,r,E),tries:e}}if(j){const t=z(import.meta.url);Dt(process.argv[2],t,V())}else H.addListener("message",async t=>{if(t.type==="process")H.postMessage(await St(t));else if(t.type==="merge")H.postMessage(Ht(t));else throw new Error("Unknown message type")}); +import{availableParallelism as V}from"node:os";import{fileURLToPath as z}from"node:url";import{isMainThread as j,parentPort as S}from"node:worker_threads";import{createWriteStream as q,createReadStream as J}from"node:fs";import{open as Q}from"fs/promises";import{Worker as tt}from"worker_threads";const L=1e4,et=100,x=107,rt=16384,nt=1048576,ot=1048576,at=152e-6,st=16384,it=1,_t=512,ct=45,U=10,W=59,P=48,C=32,Et=216;function F(t,r,e){return t>r?t<=e?t:e:r}async function ft(t,r,e,u=0){const i=await Q(t);try{const a=(await i.stat()).size,E=Math.max(u,Math.floor(a/r)),c=Buffer.allocUnsafe(e),o=[];let s=0;for(let _=E;_=0&&ft.length&&(t=G(t,a+O)),t[g]+=O,t[i]=a,t[a]=t[K]),i=a}return[t,i]}function b(t=0,r=It){r=Math.max(Z,r);const e=new Int32Array(new SharedArrayBuffer(r<<2));return e[g]=Z,e[K]=t,e}function G(t,r=0){const e=t[g];r=Math.max(r,Math.ceil(e*lt));const u=new Int32Array(new SharedArrayBuffer(r<<2));for(let i=0;it[o].length&&(t[o]=G(t[o],n+H),i.add(o)),t[o][g]+=H,t[o][s]=n,t[o][n]=w,t[o][n+D]=R;else{const I=t[o][n];o!==I&&(n=t[o][n+D]),a.push([I,n,w,R])}}s+=y,l+=y}}a.splice(0,E)}while(a.length>0);return Array.from(i)}function pt(t,r,e,u,i="",a){const E=new Array(r.length+1);E[0]=[e,p+N,0];let c=0,o=!1;do{let[s,_,l]=E[c];if(l>=k){--c;continue}E[c][1]+=y,++E[c][2];let f=t[s][_];if(f===h)continue;const T=t[s][f];s!==T&&(f=t[s][f+D],s=T),r[c]=l+C,E[++c]=[s,f+N,0];const R=t[s][f+d];R!==h&&(o&&u.write(i),o=!0,a(u,r,c,R))}while(c>=0)}function yt(t){const r=new tt(t);return r.on("error",e=>{throw e}),r.on("messageerror",e=>{throw e}),r.on("exit",e=>{if(e>1||e<0)throw new Error(`Worker ${r.threadId} exited with code ${e}`)}),r}function v(t,r){return new Promise(e=>{t.once("message",e),t.postMessage(r)})}async function Dt(t,r,e,u=""){e=F(e,it,_t);const i=await ft(t,e,x,st);e=i.length;const a=new SharedArrayBuffer(L*e+1<<4),E=new Int16Array(a),c=new Int16Array(a,2),o=new Uint32Array(a,4),s=new Float64Array(a,8),_=new Array(e),l=[],f=new Array(e);for(let n=0;n{const M=m.id;for(_[m.id]=m.trie;l.length>0;){const A=await v(I,{type:"merge",a:M,b:l.pop(),counts:o,maxes:c,mins:E,sums:s,tries:_});for(const X of A.ids)_[X]=A.tries[X]}return l.push(M),I.terminate()})}await Promise.all(f);const T=q(u,{fd:u.length<1?1:void 0,flags:"a",highWaterMark:ot}),R=Buffer.allocUnsafe(et);T.write("{"),pt(_,R,l[0],T,", ",w),T.end(`} +`);function w(n,I,m,M){const A=Math.round(s[M<<1]/o[M<<2]);n.write(I.toString("utf8",0,m)),n.write("="),n.write((E[M<<3]/10).toFixed(1)),n.write("/"),n.write((A/10).toFixed(1)),n.write("/"),n.write((c[M<<3]/10).toFixed(1))}}const Y=11*P,$=111*P;function Ot(t,r,e){return t[r]===ct?(++r,r+4>e?Y-10*t[r]-t[r+2]:$-100*t[r]-10*t[r+1]-t[r+3]):r+4>e?10*t[r]+t[r+2]-Y:100*t[r]+10*t[r+1]+t[r+3]-$}async function St({end:t,filePath:r,id:e,start:u,counts:i,maxes:a,mins:E,sums:c}){if(u>=t)return{id:e,trie:b(e,0)};let o=b(e),s=e*L+1;const _=Buffer.allocUnsafe(x),l=J(r,{start:u,end:t-1,highWaterMark:ut(t-u)});let f=0,T;for await(const n of l){const I=n.length;for(let m=0;m=I?a[n]:I,++i[n>>1],c[n>>2]+=I}return{id:e,trie:o}}function Ht({a:t,b:r,tries:e,counts:u,maxes:i,mins:a,sums:E}){function c(o,s){o<<=3,s<<=3,a[o]=Math.min(a[o],a[s]),i[o]=Math.max(i[o],i[s]),u[o>>1]+=u[s>>1],E[o>>2]+=E[s>>2]}return{ids:Nt(e,t,r,c),tries:e}}if(j){const t=z(import.meta.url);Dt(process.argv[2],t,V())}else S.addListener("message",async t=>{if(t.type==="process")S.postMessage(await St(t));else if(t.type==="merge")S.postMessage(Ht(t));else throw new Error("Unknown message type")}); //# sourceMappingURL=index.mjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index 6dc3bf5..7fa3b13 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1 +1 @@ -{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/constants/utf8.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/utils/parse.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n *\n * @remarks\n *\n * Changing this value affects the `count` and\n * `sum` values used for calculating a station's\n * average temperature.\n *\n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n *\n * @remarks\n *\n * Changing this value affects the `min`, `max` and `sum` values\n * used for calculating a station's min, max and avg\n * temperatures, respectively.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n *\n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n *\n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n *\n * @remarks\n *\n * This limit should be sufficient for most use cases.\n * However, feel free to adjust up or down as needed.\n *\n * There is not much basis for the current value.\n * Development was done with at most 8 workers and\n * a reasonable input file, with memory never exceeding\n * 20 MiB total across all workers.\n *\n * In theory, the challenge constraints allow for input\n * files that would require each worker using upwards of\n * 800 MiB; 10K stations with completely unique 100 byte names,\n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = trie[index /*+ TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index /*+ TRIE_PTR_IDX_IDX*/] = child;\n // Initialize node\n trie[child /* + TRIE_NODE_ID_IDX*/] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr /* + TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child /* + TRIE_NODE_ID_IDX*/];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi /* + TRIE_PTR_IDX_IDX*/];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri /*+ TRIE_NODE_ID_IDX*/];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai /*+ TRIE_PTR_IDX_IDX*/];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai /*+ TRIE_PTR_IDX_IDX*/] = li;\n // Initialize redirect\n tries[at][li /* + TRIE_XPTR_ID_IDX*/] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li /* + TRIE_NODE_ID_IDX*/];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr /* + TRIE_PTR_IDX_IDX*/];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI /* + TRIE_NODE_ID_IDX*/];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\nimport { Worker } from \"node:worker_threads\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const workers: Worker[] = new Array(maxWorkers);\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n workers[i] = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(workers[i], {\n type: \"process\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add the worker's trie\n const a = res.id;\n tries[res.id] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(workers[a], {\n type: \"merge\",\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return workers[a].terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { CHAR_MINUS, CHAR_ZERO } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CHAR_MINUS);\n b[min + ~sign] = CHAR_ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CHAR_MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { parseDouble } from \"./utils/parse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CHAR_NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 4;\n if (buffer[semI - 2] === CHAR_SEMICOLON) {\n semI -= 2;\n } else if (buffer[semI - 1] === CHAR_SEMICOLON) {\n semI -= 1;\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Request } from \"./types/request\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === \"process\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","MIN_WORKERS","MAX_WORKERS","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","unmerged","workers","tasks","a","out","createWriteStream","printStation","name","nameLen","vi","avg","CHAR_ZERO_11","CHAR_ZERO_111","parseDouble","b","stations","createReadStream","bufI","leaf","chunk","N","semI","tempV","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/constants/utf8.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/utils/parse.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n *\n * @remarks\n *\n * Changing this value affects the `count` and\n * `sum` values used for calculating a station's\n * average temperature.\n *\n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n *\n * @remarks\n *\n * Changing this value affects the `min`, `max` and `sum` values\n * used for calculating a station's min, max and avg\n * temperatures, respectively.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n *\n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n *\n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n *\n * @remarks\n *\n * This limit should be sufficient for most use cases.\n * However, feel free to adjust up or down as needed.\n *\n * There is not much basis for the current value.\n * Development was done with at most 8 workers and\n * a reasonable input file, with memory never exceeding\n * 20 MiB total across all workers.\n *\n * In theory, the challenge constraints allow for input\n * files that would require each worker using upwards of\n * 800 MiB; 10K stations with completely unique 100 byte names,\n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = trie[index /*+ TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index /*+ TRIE_PTR_IDX_IDX*/] = child;\n // Initialize node\n trie[child /* + TRIE_NODE_ID_IDX*/] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr /* + TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child /* + TRIE_NODE_ID_IDX*/];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi /* + TRIE_PTR_IDX_IDX*/];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri /*+ TRIE_NODE_ID_IDX*/];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai /*+ TRIE_PTR_IDX_IDX*/];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai /*+ TRIE_PTR_IDX_IDX*/] = li;\n // Initialize redirect\n tries[at][li /* + TRIE_XPTR_ID_IDX*/] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li /* + TRIE_NODE_ID_IDX*/];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr /* + TRIE_PTR_IDX_IDX*/];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI /* + TRIE_NODE_ID_IDX*/];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: \"process\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[res.id] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: \"merge\",\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { CHAR_MINUS, CHAR_ZERO } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CHAR_MINUS);\n b[min + ~sign] = CHAR_ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CHAR_MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { parseDouble } from \"./utils/parse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CHAR_NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 4;\n if (buffer[semI - 2] === CHAR_SEMICOLON) {\n semI -= 2;\n } else if (buffer[semI - 1] === CHAR_SEMICOLON) {\n semI -= 1;\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Request } from \"./types/request\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === \"process\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","MIN_WORKERS","MAX_WORKERS","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","unmerged","tasks","a","out","createWriteStream","printStation","name","nameLen","vi","avg","CHAR_ZERO_11","CHAR_ZERO_111","parseDouble","b","stations","createReadStream","bufI","leaf","chunk","N","semI","tempV","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/src/main.ts b/src/main/nodejs/havelessbemore/src/main.ts index fa51bd5..ab9115b 100644 --- a/src/main/nodejs/havelessbemore/src/main.ts +++ b/src/main/nodejs/havelessbemore/src/main.ts @@ -62,7 +62,7 @@ export async function run( start: chunks[i][0], sums, }).then(async (res) => { - // Add the worker's trie + // Add result to trie array const a = res.id; tries[res.id] = res.trie; // Merge with other tries @@ -77,6 +77,7 @@ export async function run( sums, tries, }); + // Update the trie array for (const id of res.ids) { tries[id] = res.tries[id]; } diff --git a/src/main/nodejs/havelessbemore/src/types/response.ts b/src/main/nodejs/havelessbemore/src/types/response.ts index 07f033b..158c809 100644 --- a/src/main/nodejs/havelessbemore/src/types/response.ts +++ b/src/main/nodejs/havelessbemore/src/types/response.ts @@ -1,3 +1 @@ -export interface Response { -} - \ No newline at end of file +export interface Response {} From 7e6ccb11a9daf8af6bb556e18672645d4a4d01c8 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Sat, 25 May 2024 12:51:04 -0400 Subject: [PATCH 38/69] Disable eslint rule for Response type --- src/main/nodejs/havelessbemore/src/types/response.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/nodejs/havelessbemore/src/types/response.ts b/src/main/nodejs/havelessbemore/src/types/response.ts index 158c809..8cd8ada 100644 --- a/src/main/nodejs/havelessbemore/src/types/response.ts +++ b/src/main/nodejs/havelessbemore/src/types/response.ts @@ -1 +1,2 @@ +// eslint-disable-next-line @typescript-eslint/no-empty-interface export interface Response {} From a5cd0c815e60e10494f3efff332b489dfa679e04 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Sat, 25 May 2024 12:51:48 -0400 Subject: [PATCH 39/69] Change builder from rollup to esbuild --- .../nodejs/havelessbemore/esbuild.config.js | 20 + .../nodejs/havelessbemore/package-lock.json | 778 +++--------------- src/main/nodejs/havelessbemore/package.json | 8 +- .../nodejs/havelessbemore/rollup.config.ts | 49 -- src/main/nodejs/havelessbemore/tsconfig.json | 2 +- 5 files changed, 119 insertions(+), 738 deletions(-) create mode 100644 src/main/nodejs/havelessbemore/esbuild.config.js delete mode 100644 src/main/nodejs/havelessbemore/rollup.config.ts diff --git a/src/main/nodejs/havelessbemore/esbuild.config.js b/src/main/nodejs/havelessbemore/esbuild.config.js new file mode 100644 index 0000000..6465df1 --- /dev/null +++ b/src/main/nodejs/havelessbemore/esbuild.config.js @@ -0,0 +1,20 @@ +import * as esbuild from "esbuild"; + +import pkg from "./package.json" with { type: "json" }; + +/** @type {import('esbuild').BuildOptions} */ +const options = { + entryPoints: ["src/index.ts"], + bundle: true, + drop: ["console"], + minify: false, + platform: "node", + sourcemap: true, + target: "ESNext", +}; + +await esbuild.build({ + ...options, + format: "esm", + outfile: pkg.module, +}); diff --git a/src/main/nodejs/havelessbemore/package-lock.json b/src/main/nodejs/havelessbemore/package-lock.json index 85d7206..ff95612 100644 --- a/src/main/nodejs/havelessbemore/package-lock.json +++ b/src/main/nodejs/havelessbemore/package-lock.json @@ -6,16 +6,12 @@ "": { "license": "MIT", "devDependencies": { - "@rollup/plugin-typescript": "^11.1.6", "@types/node": "^20.10.6", - "esbuild": "^0.21.2", + "esbuild": "^0.21.4", "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", "prettier": "^3.2.5", "rimraf": "^5.0.7", - "rollup": "^4.17.2", - "rollup-plugin-esbuild": "^6.1.1", - "rollup-plugin-license": "^3.4.0", "tinybench": "^2.8.0", "tslib": "^2.6.2", "tsx": "^4.10.5", @@ -27,9 +23,9 @@ } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.3.tgz", - "integrity": "sha512-yTgnwQpFVYfvvo4SvRFB0SwrW8YjOxEoT7wfMT7Ol5v7v5LDNvSGo67aExmxOb87nQNeWPVvaGBNfQ7BXcrZ9w==", + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.4.tgz", + "integrity": "sha512-Zrm+B33R4LWPLjDEVnEqt2+SLTATlru1q/xYKVn8oVTbiRBGmK2VIMoIYGJDGyftnGaC788IuzGFAlb7IQ0Y8A==", "cpu": [ "ppc64" ], @@ -43,9 +39,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.3.tgz", - "integrity": "sha512-bviJOLMgurLJtF1/mAoJLxDZDL6oU5/ztMHnJQRejbJrSc9FFu0QoUoFhvi6qSKJEw9y5oGyvr9fuDtzJ30rNQ==", + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.4.tgz", + "integrity": "sha512-E7H/yTd8kGQfY4z9t3nRPk/hrhaCajfA3YSQSBrst8B+3uTcgsi8N+ZWYCaeIDsiVs6m65JPCaQN/DxBRclF3A==", "cpu": [ "arm" ], @@ -59,9 +55,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.3.tgz", - "integrity": "sha512-c+ty9necz3zB1Y+d/N+mC6KVVkGUUOcm4ZmT5i/Fk5arOaY3i6CA3P5wo/7+XzV8cb4GrI/Zjp8NuOQ9Lfsosw==", + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.4.tgz", + "integrity": "sha512-fYFnz+ObClJ3dNiITySBUx+oNalYUT18/AryMxfovLkYWbutXsct3Wz2ZWAcGGppp+RVVX5FiXeLYGi97umisA==", "cpu": [ "arm64" ], @@ -75,9 +71,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.3.tgz", - "integrity": "sha512-JReHfYCRK3FVX4Ra+y5EBH1b9e16TV2OxrPAvzMsGeES0X2Ndm9ImQRI4Ket757vhc5XBOuGperw63upesclRw==", + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.4.tgz", + "integrity": "sha512-mDqmlge3hFbEPbCWxp4fM6hqq7aZfLEHZAKGP9viq9wMUBVQx202aDIfc3l+d2cKhUJM741VrCXEzRFhPDKH3Q==", "cpu": [ "x64" ], @@ -91,9 +87,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.3.tgz", - "integrity": "sha512-U3fuQ0xNiAkXOmQ6w5dKpEvXQRSpHOnbw7gEfHCRXPeTKW9sBzVck6C5Yneb8LfJm0l6le4NQfkNPnWMSlTFUQ==", + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.4.tgz", + "integrity": "sha512-72eaIrDZDSiWqpmCzVaBD58c8ea8cw/U0fq/PPOTqE3c53D0xVMRt2ooIABZ6/wj99Y+h4ksT/+I+srCDLU9TA==", "cpu": [ "arm64" ], @@ -107,9 +103,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.3.tgz", - "integrity": "sha512-3m1CEB7F07s19wmaMNI2KANLcnaqryJxO1fXHUV5j1rWn+wMxdUYoPyO2TnAbfRZdi7ADRwJClmOwgT13qlP3Q==", + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.4.tgz", + "integrity": "sha512-uBsuwRMehGmw1JC7Vecu/upOjTsMhgahmDkWhGLWxIgUn2x/Y4tIwUZngsmVb6XyPSTXJYS4YiASKPcm9Zitag==", "cpu": [ "x64" ], @@ -123,9 +119,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.3.tgz", - "integrity": "sha512-fsNAAl5pU6wmKHq91cHWQT0Fz0vtyE1JauMzKotrwqIKAswwP5cpHUCxZNSTuA/JlqtScq20/5KZ+TxQdovU/g==", + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.4.tgz", + "integrity": "sha512-8JfuSC6YMSAEIZIWNL3GtdUT5NhUA/CMUCpZdDRolUXNAXEE/Vbpe6qlGLpfThtY5NwXq8Hi4nJy4YfPh+TwAg==", "cpu": [ "arm64" ], @@ -139,9 +135,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.3.tgz", - "integrity": "sha512-tci+UJ4zP5EGF4rp8XlZIdq1q1a/1h9XuronfxTMCNBslpCtmk97Q/5qqy1Mu4zIc0yswN/yP/BLX+NTUC1bXA==", + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.4.tgz", + "integrity": "sha512-8d9y9eQhxv4ef7JmXny7591P/PYsDFc4+STaxC1GBv0tMyCdyWfXu2jBuqRsyhY8uL2HU8uPyscgE2KxCY9imQ==", "cpu": [ "x64" ], @@ -155,9 +151,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.3.tgz", - "integrity": "sha512-f6kz2QpSuyHHg01cDawj0vkyMwuIvN62UAguQfnNVzbge2uWLhA7TCXOn83DT0ZvyJmBI943MItgTovUob36SQ==", + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.4.tgz", + "integrity": "sha512-2rqFFefpYmpMs+FWjkzSgXg5vViocqpq5a1PSRgT0AvSgxoXmGF17qfGAzKedg6wAwyM7UltrKVo9kxaJLMF/g==", "cpu": [ "arm" ], @@ -171,9 +167,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.3.tgz", - "integrity": "sha512-vvG6R5g5ieB4eCJBQevyDMb31LMHthLpXTc2IGkFnPWS/GzIFDnaYFp558O+XybTmYrVjxnryru7QRleJvmZ6Q==", + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.4.tgz", + "integrity": "sha512-/GLD2orjNU50v9PcxNpYZi+y8dJ7e7/LhQukN3S4jNDXCKkyyiyAz9zDw3siZ7Eh1tRcnCHAo/WcqKMzmi4eMQ==", "cpu": [ "arm64" ], @@ -187,9 +183,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.3.tgz", - "integrity": "sha512-HjCWhH7K96Na+66TacDLJmOI9R8iDWDDiqe17C7znGvvE4sW1ECt9ly0AJ3dJH62jHyVqW9xpxZEU1jKdt+29A==", + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.4.tgz", + "integrity": "sha512-pNftBl7m/tFG3t2m/tSjuYeWIffzwAZT9m08+9DPLizxVOsUl8DdFzn9HvJrTQwe3wvJnwTdl92AonY36w/25g==", "cpu": [ "ia32" ], @@ -203,9 +199,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.3.tgz", - "integrity": "sha512-BGpimEccmHBZRcAhdlRIxMp7x9PyJxUtj7apL2IuoG9VxvU/l/v1z015nFs7Si7tXUwEsvjc1rOJdZCn4QTU+Q==", + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.4.tgz", + "integrity": "sha512-cSD2gzCK5LuVX+hszzXQzlWya6c7hilO71L9h4KHwqI4qeqZ57bAtkgcC2YioXjsbfAv4lPn3qe3b00Zt+jIfQ==", "cpu": [ "loong64" ], @@ -219,9 +215,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.3.tgz", - "integrity": "sha512-5rMOWkp7FQGtAH3QJddP4w3s47iT20hwftqdm7b+loe95o8JU8ro3qZbhgMRy0VuFU0DizymF1pBKkn3YHWtsw==", + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.4.tgz", + "integrity": "sha512-qtzAd3BJh7UdbiXCrg6npWLYU0YpufsV9XlufKhMhYMJGJCdfX/G6+PNd0+v877X1JG5VmjBLUiFB0o8EUSicA==", "cpu": [ "mips64el" ], @@ -235,9 +231,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.3.tgz", - "integrity": "sha512-h0zj1ldel89V5sjPLo5H1SyMzp4VrgN1tPkN29TmjvO1/r0MuMRwJxL8QY05SmfsZRs6TF0c/IDH3u7XYYmbAg==", + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.4.tgz", + "integrity": "sha512-yB8AYzOTaL0D5+2a4xEy7OVvbcypvDR05MsB/VVPVA7nL4hc5w5Dyd/ddnayStDgJE59fAgNEOdLhBxjfx5+dg==", "cpu": [ "ppc64" ], @@ -251,9 +247,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.3.tgz", - "integrity": "sha512-dkAKcTsTJ+CRX6bnO17qDJbLoW37npd5gSNtSzjYQr0svghLJYGYB0NF1SNcU1vDcjXLYS5pO4qOW4YbFama4A==", + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.4.tgz", + "integrity": "sha512-Y5AgOuVzPjQdgU59ramLoqSSiXddu7F3F+LI5hYy/d1UHN7K5oLzYBDZe23QmQJ9PIVUXwOdKJ/jZahPdxzm9w==", "cpu": [ "riscv64" ], @@ -267,9 +263,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.3.tgz", - "integrity": "sha512-vnD1YUkovEdnZWEuMmy2X2JmzsHQqPpZElXx6dxENcIwTu+Cu5ERax6+Ke1QsE814Zf3c6rxCfwQdCTQ7tPuXA==", + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.4.tgz", + "integrity": "sha512-Iqc/l/FFwtt8FoTK9riYv9zQNms7B8u+vAI/rxKuN10HgQIXaPzKZc479lZ0x6+vKVQbu55GdpYpeNWzjOhgbA==", "cpu": [ "s390x" ], @@ -283,9 +279,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.3.tgz", - "integrity": "sha512-IOXOIm9WaK7plL2gMhsWJd+l2bfrhfilv0uPTptoRoSb2p09RghhQQp9YY6ZJhk/kqmeRt6siRdMSLLwzuT0KQ==", + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.4.tgz", + "integrity": "sha512-Td9jv782UMAFsuLZINfUpoF5mZIbAj+jv1YVtE58rFtfvoKRiKSkRGQfHTgKamLVT/fO7203bHa3wU122V/Bdg==", "cpu": [ "x64" ], @@ -299,9 +295,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.3.tgz", - "integrity": "sha512-uTgCwsvQ5+vCQnqM//EfDSuomo2LhdWhFPS8VL8xKf+PKTCrcT/2kPPoWMTs22aB63MLdGMJiE3f1PHvCDmUOw==", + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.4.tgz", + "integrity": "sha512-Awn38oSXxsPMQxaV0Ipb7W/gxZtk5Tx3+W+rAPdZkyEhQ6968r9NvtkjhnhbEgWXYbgV+JEONJ6PcdBS+nlcpA==", "cpu": [ "x64" ], @@ -315,9 +311,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.3.tgz", - "integrity": "sha512-vNAkR17Ub2MgEud2Wag/OE4HTSI6zlb291UYzHez/psiKarp0J8PKGDnAhMBcHFoOHMXHfExzmjMojJNbAStrQ==", + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.4.tgz", + "integrity": "sha512-IsUmQeCY0aU374R82fxIPu6vkOybWIMc3hVGZ3ChRwL9hA1TwY+tS0lgFWV5+F1+1ssuvvXt3HFqe8roCip8Hg==", "cpu": [ "x64" ], @@ -331,9 +327,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.3.tgz", - "integrity": "sha512-W8H9jlGiSBomkgmouaRoTXo49j4w4Kfbl6I1bIdO/vT0+0u4f20ko3ELzV3hPI6XV6JNBVX+8BC+ajHkvffIJA==", + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.4.tgz", + "integrity": "sha512-hsKhgZ4teLUaDA6FG/QIu2q0rI6I36tZVfM4DBZv3BG0mkMIdEnMbhc4xwLvLJSS22uWmaVkFkqWgIS0gPIm+A==", "cpu": [ "x64" ], @@ -347,9 +343,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.3.tgz", - "integrity": "sha512-EjEomwyLSCg8Ag3LDILIqYCZAq/y3diJ04PnqGRgq8/4O3VNlXyMd54j/saShaN4h5o5mivOjAzmU6C3X4v0xw==", + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.4.tgz", + "integrity": "sha512-UUfMgMoXPoA/bvGUNfUBFLCh0gt9dxZYIx9W4rfJr7+hKe5jxxHmfOK8YSH4qsHLLN4Ck8JZ+v7Q5fIm1huErg==", "cpu": [ "arm64" ], @@ -363,9 +359,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.3.tgz", - "integrity": "sha512-WGiE/GgbsEwR33++5rzjiYsKyHywE8QSZPF7Rfx9EBfK3Qn3xyR6IjyCr5Uk38Kg8fG4/2phN7sXp4NPWd3fcw==", + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.4.tgz", + "integrity": "sha512-yIxbspZb5kGCAHWm8dexALQ9en1IYDfErzjSEq1KzXFniHv019VT3mNtTK7t8qdy4TwT6QYHI9sEZabONHg+aw==", "cpu": [ "ia32" ], @@ -379,9 +375,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.3.tgz", - "integrity": "sha512-xRxC0jaJWDLYvcUvjQmHCJSfMrgmUuvsoXgDeU/wTorQ1ngDdUBuFtgY3W1Pc5sprGAvZBtWdJX7RPg/iZZUqA==", + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.4.tgz", + "integrity": "sha512-sywLRD3UK/qRJt0oBwdpYLBibk7KiRfbswmWRDabuncQYSlf8aLEEUor/oP6KRz8KEG+HoiVLBhPRD5JWjS8Sg==", "cpu": [ "x64" ], @@ -527,12 +523,6 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -578,268 +568,6 @@ "node": ">=14" } }, - "node_modules/@rollup/plugin-typescript": { - "version": "11.1.6", - "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-11.1.6.tgz", - "integrity": "sha512-R92yOmIACgYdJ7dJ97p4K69I8gg6IEHt8M7dUBxN3W6nrO8uUxX5ixl0yU/N3aZTi8WhPuICvOHXQvF6FaykAA==", - "dev": true, - "dependencies": { - "@rollup/pluginutils": "^5.1.0", - "resolve": "^1.22.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^2.14.0||^3.0.0||^4.0.0", - "tslib": "*", - "typescript": ">=3.7.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - }, - "tslib": { - "optional": true - } - } - }, - "node_modules/@rollup/pluginutils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz", - "integrity": "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==", - "dev": true, - "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.17.2.tgz", - "integrity": "sha512-NM0jFxY8bB8QLkoKxIQeObCaDlJKewVlIEkuyYKm5An1tdVZ966w2+MPQ2l8LBZLjR+SgyV+nRkTIunzOYBMLQ==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.17.2.tgz", - "integrity": "sha512-yeX/Usk7daNIVwkq2uGoq2BYJKZY1JfyLTaHO/jaiSwi/lsf8fTFoQW/n6IdAsx5tx+iotu2zCJwz8MxI6D/Bw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.17.2.tgz", - "integrity": "sha512-kcMLpE6uCwls023+kknm71ug7MZOrtXo+y5p/tsg6jltpDtgQY1Eq5sGfHcQfb+lfuKwhBmEURDga9N0ol4YPw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.17.2.tgz", - "integrity": "sha512-AtKwD0VEx0zWkL0ZjixEkp5tbNLzX+FCqGG1SvOu993HnSz4qDI6S4kGzubrEJAljpVkhRSlg5bzpV//E6ysTQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.17.2.tgz", - "integrity": "sha512-3reX2fUHqN7sffBNqmEyMQVj/CKhIHZd4y631duy0hZqI8Qoqf6lTtmAKvJFYa6bhU95B1D0WgzHkmTg33In0A==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.17.2.tgz", - "integrity": "sha512-uSqpsp91mheRgw96xtyAGP9FW5ChctTFEoXP0r5FAzj/3ZRv3Uxjtc7taRQSaQM/q85KEKjKsZuiZM3GyUivRg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.17.2.tgz", - "integrity": "sha512-EMMPHkiCRtE8Wdk3Qhtciq6BndLtstqZIroHiiGzB3C5LDJmIZcSzVtLRbwuXuUft1Cnv+9fxuDtDxz3k3EW2A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.17.2.tgz", - "integrity": "sha512-NMPylUUZ1i0z/xJUIx6VUhISZDRT+uTWpBcjdv0/zkp7b/bQDF+NfnfdzuTiB1G6HTodgoFa93hp0O1xl+/UbA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.17.2.tgz", - "integrity": "sha512-T19My13y8uYXPw/L/k0JYaX1fJKFT/PWdXiHr8mTbXWxjVF1t+8Xl31DgBBvEKclw+1b00Chg0hxE2O7bTG7GQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.17.2.tgz", - "integrity": "sha512-BOaNfthf3X3fOWAB+IJ9kxTgPmMqPPH5f5k2DcCsRrBIbWnaJCgX2ll77dV1TdSy9SaXTR5iDXRL8n7AnoP5cg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.17.2.tgz", - "integrity": "sha512-W0UP/x7bnn3xN2eYMql2T/+wpASLE5SjObXILTMPUBDB/Fg/FxC+gX4nvCfPBCbNhz51C+HcqQp2qQ4u25ok6g==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.17.2.tgz", - "integrity": "sha512-Hy7pLwByUOuyaFC6mAr7m+oMC+V7qyifzs/nW2OJfC8H4hbCzOX07Ov0VFk/zP3kBsELWNFi7rJtgbKYsav9QQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.17.2.tgz", - "integrity": "sha512-h1+yTWeYbRdAyJ/jMiVw0l6fOOm/0D1vNLui9iPuqgRGnXA0u21gAqOyB5iHjlM9MMfNOm9RHCQ7zLIzT0x11Q==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.17.2.tgz", - "integrity": "sha512-tmdtXMfKAjy5+IQsVtDiCfqbynAQE/TQRpWdVataHmhMb9DCoJxp9vLcCBjEQWMiUYxO1QprH/HbY9ragCEFLA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.17.2.tgz", - "integrity": "sha512-7II/QCSTAHuE5vdZaQEwJq2ZACkBpQDOmQsE6D6XUbnBHW8IAhm4eTufL6msLJorzrHDFv3CF8oCA/hSIRuZeQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.17.2.tgz", - "integrity": "sha512-TGGO7v7qOq4CYmSBVEYpI1Y5xDuCEnbVC5Vth8mOsW0gDSzxNrVERPc790IGHsrT2dQSimgMr9Ub3Y1Jci5/8w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", - "dev": true - }, "node_modules/@types/node": { "version": "20.12.12", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz", @@ -1131,15 +859,6 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, - "node_modules/array-find-index": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", - "integrity": "sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/array-union": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", @@ -1220,12 +939,6 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/commenting": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/commenting/-/commenting-1.1.0.tgz", - "integrity": "sha512-YeNK4tavZwtH7jEgK1ZINXzLKm6DZdEMfsaaieOsCAN0S8vsY7UeuO3Q7d/M018EFgE+IeUAuBOKkFccBZsUZA==", - "dev": true - }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1305,16 +1018,10 @@ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true }, - "node_modules/es-module-lexer": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.5.3.tgz", - "integrity": "sha512-i1gCgmR9dCl6Vil6UKPI/trA69s08g/syhiDK9TG0Nf1RJjjFI+AzoWW7sPufzkgYAn861skuCwJa0pIIHYxvg==", - "dev": true - }, "node_modules/esbuild": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.3.tgz", - "integrity": "sha512-Kgq0/ZsAPzKrbOjCQcjoSmPoWhlcVnGAUo7jvaLHoxW1Drto0KGkR1xBNg2Cp43b9ImvxmPEJZ9xkfcnqPsfBw==", + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.4.tgz", + "integrity": "sha512-sFMcNNrj+Q0ZDolrp5pDhH0nRPN9hLIM3fRPwgbLYJeSHHgnXSnbV3xYgSVuOeLWH9c73VwmEverVzupIv5xuA==", "dev": true, "hasInstallScript": true, "bin": { @@ -1324,29 +1031,29 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.3", - "@esbuild/android-arm": "0.21.3", - "@esbuild/android-arm64": "0.21.3", - "@esbuild/android-x64": "0.21.3", - "@esbuild/darwin-arm64": "0.21.3", - "@esbuild/darwin-x64": "0.21.3", - "@esbuild/freebsd-arm64": "0.21.3", - "@esbuild/freebsd-x64": "0.21.3", - "@esbuild/linux-arm": "0.21.3", - "@esbuild/linux-arm64": "0.21.3", - "@esbuild/linux-ia32": "0.21.3", - "@esbuild/linux-loong64": "0.21.3", - "@esbuild/linux-mips64el": "0.21.3", - "@esbuild/linux-ppc64": "0.21.3", - "@esbuild/linux-riscv64": "0.21.3", - "@esbuild/linux-s390x": "0.21.3", - "@esbuild/linux-x64": "0.21.3", - "@esbuild/netbsd-x64": "0.21.3", - "@esbuild/openbsd-x64": "0.21.3", - "@esbuild/sunos-x64": "0.21.3", - "@esbuild/win32-arm64": "0.21.3", - "@esbuild/win32-ia32": "0.21.3", - "@esbuild/win32-x64": "0.21.3" + "@esbuild/aix-ppc64": "0.21.4", + "@esbuild/android-arm": "0.21.4", + "@esbuild/android-arm64": "0.21.4", + "@esbuild/android-x64": "0.21.4", + "@esbuild/darwin-arm64": "0.21.4", + "@esbuild/darwin-x64": "0.21.4", + "@esbuild/freebsd-arm64": "0.21.4", + "@esbuild/freebsd-x64": "0.21.4", + "@esbuild/linux-arm": "0.21.4", + "@esbuild/linux-arm64": "0.21.4", + "@esbuild/linux-ia32": "0.21.4", + "@esbuild/linux-loong64": "0.21.4", + "@esbuild/linux-mips64el": "0.21.4", + "@esbuild/linux-ppc64": "0.21.4", + "@esbuild/linux-riscv64": "0.21.4", + "@esbuild/linux-s390x": "0.21.4", + "@esbuild/linux-x64": "0.21.4", + "@esbuild/netbsd-x64": "0.21.4", + "@esbuild/openbsd-x64": "0.21.4", + "@esbuild/sunos-x64": "0.21.4", + "@esbuild/win32-arm64": "0.21.4", + "@esbuild/win32-ia32": "0.21.4", + "@esbuild/win32-x64": "0.21.4" } }, "node_modules/escape-string-regexp": { @@ -1506,12 +1213,6 @@ "node": ">=4.0" } }, - "node_modules/estree-walker": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", - "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", - "dev": true - }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -1707,15 +1408,6 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/get-tsconfig": { "version": "4.7.5", "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.5.tgz", @@ -1836,18 +1528,6 @@ "node": ">=8" } }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/ignore": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", @@ -1898,18 +1578,6 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, - "node_modules/is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", - "dev": true, - "dependencies": { - "hasown": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -2049,12 +1717,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -2070,15 +1732,6 @@ "node": "14 || >=16.14" } }, - "node_modules/magic-string": { - "version": "0.30.10", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", - "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", - "dev": true, - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" - } - }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -2134,30 +1787,6 @@ "node": ">=16 || 14 >=14.17" } }, - "node_modules/mkdirp": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", - "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", - "dev": true, - "bin": { - "mkdirp": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/moment": { - "version": "2.30.1", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", - "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", - "dev": true, - "engines": { - "node": "*" - } - }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -2226,18 +1855,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/package-name-regex": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/package-name-regex/-/package-name-regex-2.0.6.tgz", - "integrity": "sha512-gFL35q7kbE/zBaPA3UKhp2vSzcPYx2ecbYuwv1ucE9Il6IIgBDweBlH8D68UFGZic2MkllKa2KHCfC1IQBQUYA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/dword-design" - } - }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -2277,12 +1894,6 @@ "node": ">=8" } }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, "node_modules/path-scurry": { "version": "1.11.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", @@ -2308,18 +1919,6 @@ "node": ">=8" } }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -2373,23 +1972,6 @@ } ] }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", @@ -2436,103 +2018,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/rollup": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.17.2.tgz", - "integrity": "sha512-/9ClTJPByC0U4zNLowV1tMBe8yMEAxewtR3cUNX5BoEpGH3dQEWpJLr6CLp0fPdYRF/fzVOgvDb1zXuakwF5kQ==", - "dev": true, - "dependencies": { - "@types/estree": "1.0.5" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.17.2", - "@rollup/rollup-android-arm64": "4.17.2", - "@rollup/rollup-darwin-arm64": "4.17.2", - "@rollup/rollup-darwin-x64": "4.17.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.17.2", - "@rollup/rollup-linux-arm-musleabihf": "4.17.2", - "@rollup/rollup-linux-arm64-gnu": "4.17.2", - "@rollup/rollup-linux-arm64-musl": "4.17.2", - "@rollup/rollup-linux-powerpc64le-gnu": "4.17.2", - "@rollup/rollup-linux-riscv64-gnu": "4.17.2", - "@rollup/rollup-linux-s390x-gnu": "4.17.2", - "@rollup/rollup-linux-x64-gnu": "4.17.2", - "@rollup/rollup-linux-x64-musl": "4.17.2", - "@rollup/rollup-win32-arm64-msvc": "4.17.2", - "@rollup/rollup-win32-ia32-msvc": "4.17.2", - "@rollup/rollup-win32-x64-msvc": "4.17.2", - "fsevents": "~2.3.2" - } - }, - "node_modules/rollup-plugin-esbuild": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/rollup-plugin-esbuild/-/rollup-plugin-esbuild-6.1.1.tgz", - "integrity": "sha512-CehMY9FAqJD5OUaE/Mi1r5z0kNeYxItmRO2zG4Qnv2qWKF09J2lTy5GUzjJR354ZPrLkCj4fiBN41lo8PzBUhw==", - "dev": true, - "dependencies": { - "@rollup/pluginutils": "^5.0.5", - "debug": "^4.3.4", - "es-module-lexer": "^1.3.1", - "get-tsconfig": "^4.7.2" - }, - "engines": { - "node": ">=14.18.0" - }, - "peerDependencies": { - "esbuild": ">=0.18.0", - "rollup": "^1.20.0 || ^2.0.0 || ^3.0.0 || ^4.0.0" - } - }, - "node_modules/rollup-plugin-license": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/rollup-plugin-license/-/rollup-plugin-license-3.4.0.tgz", - "integrity": "sha512-Nwx4dDjoPlzR7QWcsswezxFAOC000+JLACganH3L+5toit0TEAfD4SF1DsvJR/kunHWJgqnhmzvOO+iLI1oKPw==", - "dev": true, - "dependencies": { - "commenting": "~1.1.0", - "glob": "~7.2.0", - "lodash": "~4.17.21", - "magic-string": "~0.30.0", - "mkdirp": "~3.0.0", - "moment": "~2.30.1", - "package-name-regex": "~2.0.6", - "spdx-expression-validate": "~2.0.0", - "spdx-satisfies": "~5.0.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.0.0 || ^2.0.0 || ^3.0.0 || ^4.0.0" - } - }, - "node_modules/rollup-plugin-license/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -2610,65 +2095,6 @@ "node": ">=8" } }, - "node_modules/spdx-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/spdx-compare/-/spdx-compare-1.0.0.tgz", - "integrity": "sha512-C1mDZOX0hnu0ep9dfmuoi03+eOdDoz2yvK79RxbcrVEG1NO1Ph35yW102DHWKN4pk80nwCgeMmSY5L25VE4D9A==", - "dev": true, - "dependencies": { - "array-find-index": "^1.0.2", - "spdx-expression-parse": "^3.0.0", - "spdx-ranges": "^2.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", - "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", - "dev": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-expression-validate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-validate/-/spdx-expression-validate-2.0.0.tgz", - "integrity": "sha512-b3wydZLM+Tc6CFvaRDBOF9d76oGIHNCLYFeHbftFXUWjnfZWganmDmvtM5sm1cRwJc/VDBMLyGGrsLFd1vOxbg==", - "dev": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.17", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz", - "integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==", - "dev": true - }, - "node_modules/spdx-ranges": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/spdx-ranges/-/spdx-ranges-2.1.1.tgz", - "integrity": "sha512-mcdpQFV7UDAgLpXEE/jOMqvK4LBoO0uTQg0uvXUewmEFhpiZx5yJSZITHB8w1ZahKdhfZqP5GPEOKLyEq5p8XA==", - "dev": true - }, - "node_modules/spdx-satisfies": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/spdx-satisfies/-/spdx-satisfies-5.0.1.tgz", - "integrity": "sha512-Nwor6W6gzFp8XX4neaKQ7ChV4wmpSh2sSDemMFSzHxpTw460jxFYeOn+jq4ybnSSw/5sc3pjka9MQPouksQNpw==", - "dev": true, - "dependencies": { - "spdx-compare": "^1.0.0", - "spdx-expression-parse": "^3.0.0", - "spdx-ranges": "^2.0.0" - } - }, "node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", @@ -2783,18 +2209,6 @@ "node": ">=8" } }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", diff --git a/src/main/nodejs/havelessbemore/package.json b/src/main/nodejs/havelessbemore/package.json index 11f9750..f9b63c2 100644 --- a/src/main/nodejs/havelessbemore/package.json +++ b/src/main/nodejs/havelessbemore/package.json @@ -21,21 +21,17 @@ }, "scripts": { "bench": "tsx ./benchmarks/bench.ts ../../../../measurements.txt", - "build": "rimraf dist && tsc && rollup -c --configPlugin typescript", + "build": "rimraf dist && tsc && node ./esbuild.config.js", "format": "prettier . --write", "lint": "eslint ." }, "devDependencies": { - "@rollup/plugin-typescript": "^11.1.6", "@types/node": "^20.10.6", - "esbuild": "^0.21.2", + "esbuild": "^0.21.4", "eslint": "^8.57.0", "eslint-config-prettier": "^9.1.0", "prettier": "^3.2.5", "rimraf": "^5.0.7", - "rollup": "^4.17.2", - "rollup-plugin-esbuild": "^6.1.1", - "rollup-plugin-license": "^3.4.0", "tinybench": "^2.8.0", "tslib": "^2.6.2", "tsx": "^4.10.5", diff --git a/src/main/nodejs/havelessbemore/rollup.config.ts b/src/main/nodejs/havelessbemore/rollup.config.ts deleted file mode 100644 index a67a998..0000000 --- a/src/main/nodejs/havelessbemore/rollup.config.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { RollupOptions } from "rollup"; -import esbuild from "rollup-plugin-esbuild"; -import license, { Options as LicenseOptions } from "rollup-plugin-license"; - -import pkg from "./package.json" with { type: "json" }; - -function bundle(config: RollupOptions): RollupOptions { - return { - ...config, - input: "src/index.ts", - external: (id) => !/^[./]/.test(id), - }; -} - -const licenseConfig: LicenseOptions = { - sourcemap: true, - banner: { - commentStyle: "ignored", - content: { - file: "./NOTICE", - }, - }, -}; - -export default [ - bundle({ - plugins: [ - esbuild({ - target: "ES2022", - minify: true, - }), - license(licenseConfig), - ], - output: [ - { - file: pkg.main, - format: "cjs", - sourcemap: true, - exports: "named", - }, - { - file: pkg.module, - format: "es", - sourcemap: true, - exports: "named", - }, - ], - }), -]; diff --git a/src/main/nodejs/havelessbemore/tsconfig.json b/src/main/nodejs/havelessbemore/tsconfig.json index f5c0f23..c9162b4 100644 --- a/src/main/nodejs/havelessbemore/tsconfig.json +++ b/src/main/nodejs/havelessbemore/tsconfig.json @@ -12,7 +12,7 @@ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ /* Language and Environment */ - "target": "ES2022" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + "target": "ESNext" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, "lib": [ "ESNext" ] /* Specify a set of bundled library declaration files that describe the target runtime environment. */, From da0ef678e4b96482877cfbeefebf3c40fbc0154a Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Sat, 25 May 2024 12:52:46 -0400 Subject: [PATCH 40/69] Change CHAR_CODE_ constants into CharCode const enum --- .../havelessbemore/src/constants/utf8.ts | 43 ++++++++++--------- .../nodejs/havelessbemore/src/utils/parse.ts | 14 +++--- .../nodejs/havelessbemore/src/utils/stream.ts | 4 +- src/main/nodejs/havelessbemore/src/worker.ts | 9 ++-- 4 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/main/nodejs/havelessbemore/src/constants/utf8.ts b/src/main/nodejs/havelessbemore/src/constants/utf8.ts index f2d4c20..718edd7 100644 --- a/src/main/nodejs/havelessbemore/src/constants/utf8.ts +++ b/src/main/nodejs/havelessbemore/src/constants/utf8.ts @@ -1,29 +1,30 @@ -// UTF-8 char codes -/** - * The char code for a minus sign: - - */ -export const CHAR_MINUS = 45; // "-".charCodeAt(0); +export const enum CharCode { + /** + * The char code for a minus sign: - + */ + MINUS = 45, // "-".charCodeAt(0), -/** - * The char code for a newline: \n - */ -export const CHAR_NEWLINE = 10; // "\n".charCodeAt(0); + /** + * The char code for a newline: \n + */ + NEWLINE = 10, // "\n".charCodeAt(0), -/** - * The char code for a period: . - */ -export const CHAR_PERIOD = 46; // ".".charCodeAt(0); + /** + * The char code for a period: . + */ + PERIOD = 46, // ".".charCodeAt(0), -/** - * The char code for a semicolon: ; - */ -export const CHAR_SEMICOLON = 59; // ";".charCodeAt(0); + /** + * The char code for a semicolon: , + */ + SEMICOLON = 59, // ";".charCodeAt(0), -/** - * The char code for a zero: 0 - */ -export const CHAR_ZERO = 48; // "0".charCodeAt(0); + /** + * The char code for a zero: 0 + */ + ZERO = 48, // "0".charCodeAt(0), +}; // UTF-8 constants diff --git a/src/main/nodejs/havelessbemore/src/utils/parse.ts b/src/main/nodejs/havelessbemore/src/utils/parse.ts index 6391ef0..e139897 100644 --- a/src/main/nodejs/havelessbemore/src/utils/parse.ts +++ b/src/main/nodejs/havelessbemore/src/utils/parse.ts @@ -1,7 +1,7 @@ -import { CHAR_MINUS, CHAR_ZERO } from "../constants/utf8"; +import { CharCode } from "../constants/utf8"; -export const CHAR_ZERO_11 = 11 * CHAR_ZERO; -export const CHAR_ZERO_111 = 111 * CHAR_ZERO; +export const CHAR_ZERO_11 = 11 * CharCode.ZERO; +export const CHAR_ZERO_111 = 111 * CharCode.ZERO; /** * Converts an ASCII numeric string into an integer. @@ -9,7 +9,7 @@ export const CHAR_ZERO_111 = 111 * CHAR_ZERO; * Fastest. */ export function parseDouble(b: Buffer, min: number, max: number): number { - if (b[min] === CHAR_MINUS) { + if (b[min] === CharCode.MINUS) { ++min; return min + 4 > max ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2] @@ -26,8 +26,8 @@ export function parseDouble(b: Buffer, min: number, max: number): number { * Second fastest. */ export function parseDoubleFlat(b: Buffer, min: number, max: number): number { - const sign = -(b[min] === CHAR_MINUS); - b[min + ~sign] = CHAR_ZERO; + const sign = -(b[min] === CharCode.MINUS); + b[min + ~sign] = CharCode.ZERO; return ( ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) - sign @@ -43,7 +43,7 @@ export function parseDoubleFlat(b: Buffer, min: number, max: number): number { */ export function parseDoubleQuan(b: Buffer, min: number, max: number): number { b[min - 1] = 0; - const sign = -(b[min] === CHAR_MINUS); + const sign = -(b[min] === CharCode.MINUS); const signMask = -(min + 4 >= max) & sign & 0xff000000; let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f; v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22); diff --git a/src/main/nodejs/havelessbemore/src/utils/stream.ts b/src/main/nodejs/havelessbemore/src/utils/stream.ts index 31f846f..2295eaf 100644 --- a/src/main/nodejs/havelessbemore/src/utils/stream.ts +++ b/src/main/nodejs/havelessbemore/src/utils/stream.ts @@ -1,11 +1,11 @@ import { open } from "fs/promises"; -import { CHAR_NEWLINE } from "../constants/utf8"; import { HIGH_WATER_MARK_MAX, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_RATIO, } from "../constants/stream"; +import { CharCode } from "../constants/utf8"; /** * Clamp a value within a given range. @@ -60,7 +60,7 @@ export async function getFileChunks( // Read a line at the intended end index const res = await file.read(buffer, 0, maxLineLength, end); // Find the nearest newline ('\n') character - const newline = buffer.indexOf(CHAR_NEWLINE); + const newline = buffer.indexOf(CharCode.NEWLINE); // If found if (newline >= 0 && newline < res.bytesRead) { // Align end with the newline diff --git a/src/main/nodejs/havelessbemore/src/worker.ts b/src/main/nodejs/havelessbemore/src/worker.ts index 0dd3297..1502b2c 100644 --- a/src/main/nodejs/havelessbemore/src/worker.ts +++ b/src/main/nodejs/havelessbemore/src/worker.ts @@ -3,8 +3,6 @@ import { createReadStream } from "node:fs"; import type { ProcessRequest } from "./types/processRequest"; import type { ProcessResponse } from "./types/processResponse"; -import { CHAR_SEMICOLON } from "./constants/utf8"; -import { CHAR_NEWLINE } from "./constants/utf8"; import { ENTRY_MAX_LEN, MAX_STATIONS } from "./constants/constraints"; import { TRIE_NODE_VALUE_IDX, TRIE_NULL } from "./constants/utf8Trie"; import { getHighWaterMark } from "./utils/stream"; @@ -12,6 +10,7 @@ import { add, createTrie, mergeLeft } from "./utils/utf8Trie"; import { MergeRequest } from "./types/mergeRequest"; import { MergeResponse } from "./types/mergeResponse"; import { parseDouble } from "./utils/parse"; +import { CharCode } from "./constants/utf8"; export async function run({ end, @@ -49,16 +48,16 @@ export async function run({ const N = chunk.length; for (let i = 0; i < N; ++i) { // If not newline - if (chunk[i] !== CHAR_NEWLINE) { + if (chunk[i] !== CharCode.NEWLINE) { buffer[bufI++] = chunk[i]; continue; } // Get semicolon let semI = bufI - 4; - if (buffer[semI - 2] === CHAR_SEMICOLON) { + if (buffer[semI - 2] === CharCode.SEMICOLON) { semI -= 2; - } else if (buffer[semI - 1] === CHAR_SEMICOLON) { + } else if (buffer[semI - 1] === CharCode.SEMICOLON) { semI -= 1; } From 79dd58fb362bef44583aa23f71b49c673da084d2 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Sat, 25 May 2024 12:56:08 -0400 Subject: [PATCH 41/69] Change UTF8_ constants into UTF8 const enum --- .../havelessbemore/src/constants/utf8.ts | 72 ++++++++++--------- .../havelessbemore/src/constants/utf8Trie.ts | 6 +- .../havelessbemore/src/utils/utf8Trie.ts | 8 +-- 3 files changed, 44 insertions(+), 42 deletions(-) diff --git a/src/main/nodejs/havelessbemore/src/constants/utf8.ts b/src/main/nodejs/havelessbemore/src/constants/utf8.ts index 718edd7..eea7135 100644 --- a/src/main/nodejs/havelessbemore/src/constants/utf8.ts +++ b/src/main/nodejs/havelessbemore/src/constants/utf8.ts @@ -28,43 +28,45 @@ export const enum CharCode { // UTF-8 constants -/** - * The minimum value of a UTF-8 byte. - * - * Ignores C0 control codes from U+0000 to U+001F. - * - * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes} - */ -export const UTF8_BYTE_MIN = 32; +export const enum UTF8 { + /** + * The minimum value of a UTF-8 byte. + * + * Ignores C0 control codes from U+0000 to U+001F. + * + * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes} + */ + BYTE_MIN = 32, -/** - * The maximum value of a UTF-8 byte. - * - * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding} - */ -export const UTF8_BYTE_MAX = 0b11110111; + /** + * The maximum value of a UTF-8 byte. + * + * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding} + */ + BYTE_MAX = 0b11110111, -/** - * The number of possible values in a UTF-8 byte. - */ -export const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1; + /** + * The number of possible values in a UTF-8 byte. + */ + BYTE_SPAN = BYTE_MAX - BYTE_MIN + 1, -/* -export const UTF8_B0_1B_LEAD = 0b00000000; -export const UTF8_BN_LEAD = 0b10000000; -export const UTF8_B0_2B_LEAD = 0b11000000; -export const UTF8_B0_3B_LEAD = 0b11100000; -export const UTF8_B0_4B_LEAD = 0b11110000; + /* + B0_1B_LEAD = 0b00000000, + BN_LEAD = 0b10000000, + B0_2B_LEAD = 0b11000000, + B0_3B_LEAD = 0b11100000, + B0_4B_LEAD = 0b11110000, -export const UTF8_B0_1B_LEAD_MASK = 0b10000000; -export const UTF8_BN_LEAD_MASK = 0b11000000; -export const UTF8_B0_2B_LEAD_MASK = 0b11100000; -export const UTF8_B0_3B_LEAD_MASK = 0b11110000; -export const UTF8_B0_4B_LEAD_MASK = 0b11111000; + B0_1B_LEAD_MASK = 0b10000000, + BN_LEAD_MASK = 0b11000000, + B0_2B_LEAD_MASK = 0b11100000, + B0_3B_LEAD_MASK = 0b11110000, + B0_4B_LEAD_MASK = 0b11111000, -export const UTF8_B0_1B_MAX = 0b01111111; -export const UTF8_BN_MAX = 0b10111111; -export const UTF8_B0_2B_MAX = 0b11011111; -export const UTF8_B0_3B_MAX = 0b11101111; -export const UTF8_B0_4B_MAX = 0b11110111; -*/ + B0_1B_MAX = 0b01111111, + BN_MAX = 0b10111111, + B0_2B_MAX = 0b11011111, + B0_3B_MAX = 0b11101111, + B0_4B_MAX = 0b11110111, + */ +}; diff --git a/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts b/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts index 4490745..5463c44 100644 --- a/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts +++ b/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts @@ -1,10 +1,10 @@ -import { UTF8_BYTE_SPAN } from "./utf8"; - // Configurable constants. // // Controls trie behavior such as the default // allocated size and the growth factor when resizing. +import { UTF8 } from "./utf8"; + /** * The default initial size of a trie. */ @@ -54,7 +54,7 @@ export const TRIE_NODE_VALUE_MEM = 1; // The node's children pointers export const TRIE_NODE_CHILDREN_IDX = 2; -export const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN; +export const TRIE_NODE_CHILDREN_LEN = UTF8.BYTE_SPAN; export const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN; export const TRIE_NODE_MEM = diff --git a/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts b/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts index 88ee938..06c4dd0 100644 --- a/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts +++ b/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts @@ -17,7 +17,7 @@ import { TRIE_NODE_CHILDREN_MEM, TRIE_NODE_CHILDREN_LEN, } from "../constants/utf8Trie"; -import { UTF8_BYTE_MIN } from "../constants/utf8"; +import { UTF8 } from "../constants/utf8"; export function add( trie: Int32Array, @@ -28,7 +28,7 @@ export function add( let index = TRIE_ROOT_IDX; while (min < max) { index += - TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN); + TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */ (key[min++] - UTF8.BYTE_MIN); let child = trie[index /*+ TRIE_PTR_IDX_IDX*/]; if (child === TRIE_NULL) { // Allocate node @@ -60,7 +60,7 @@ export function get( const ptr = node + TRIE_NODE_CHILDREN_IDX + - /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN); + /*TRIE_PTR_MEM * */ (key[min++] - UTF8.BYTE_MIN); let child = tries[trie][ptr /* + TRIE_PTR_IDX_IDX*/]; if (child === TRIE_NULL) { return undefined; @@ -221,7 +221,7 @@ export function print( } // Add the child to the stack - key[top] = numChild + UTF8_BYTE_MIN; + key[top] = numChild + UTF8.BYTE_MIN; stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0]; // Print value, if any From c327ef0ab0838a6eab80632a7e42143877b21811 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Sat, 25 May 2024 13:11:54 -0400 Subject: [PATCH 42/69] Update worker, stream and constraint constants --- src/main/nodejs/havelessbemore/dist/index.cjs | 29 -- .../nodejs/havelessbemore/dist/index.cjs.map | 1 - src/main/nodejs/havelessbemore/dist/index.mjs | 471 ++++++++++++++++-- .../nodejs/havelessbemore/dist/index.mjs.map | 8 +- .../havelessbemore/src/constants/brc.ts | 74 +++ .../havelessbemore/src/constants/config.ts | 56 +++ .../src/constants/constraints.ts | 69 --- .../havelessbemore/src/constants/stream.ts | 25 - .../havelessbemore/src/constants/utf8.ts | 83 ++- .../havelessbemore/src/constants/workers.ts | 28 -- src/main/nodejs/havelessbemore/src/main.ts | 23 +- .../nodejs/havelessbemore/src/utils/stream.ts | 10 +- src/main/nodejs/havelessbemore/src/worker.ts | 6 +- 13 files changed, 637 insertions(+), 246 deletions(-) delete mode 100644 src/main/nodejs/havelessbemore/dist/index.cjs delete mode 100644 src/main/nodejs/havelessbemore/dist/index.cjs.map create mode 100644 src/main/nodejs/havelessbemore/src/constants/brc.ts create mode 100644 src/main/nodejs/havelessbemore/src/constants/config.ts delete mode 100644 src/main/nodejs/havelessbemore/src/constants/constraints.ts delete mode 100644 src/main/nodejs/havelessbemore/src/constants/stream.ts delete mode 100644 src/main/nodejs/havelessbemore/src/constants/workers.ts diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs b/src/main/nodejs/havelessbemore/dist/index.cjs deleted file mode 100644 index 1dac372..0000000 --- a/src/main/nodejs/havelessbemore/dist/index.cjs +++ /dev/null @@ -1,29 +0,0 @@ -/*! - * https://github.com/havelessbemore/1brc-nodejs - * - * MIT License - * - * Copyright (C) 2024-2024 Michael Rojas (https://github.com/havelessbemore) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -"use strict";var j=require("node:os"),z=require("node:url"),p=require("node:worker_threads"),X=require("node:fs"),J=require("fs/promises"),Q=require("worker_threads"),U=typeof document<"u"?document.currentScript:null;const x=1e4,ee=100,P=107,te=16384,re=1048576,ne=1048576,oe=152e-6,ae=16384,se=1,ie=512,_e=45,W=10,C=59,k=48,v=32,ce=216;function F(e,r,t){return e>r?e<=t?e:t:r}async function ue(e,r,t,f=0){const i=await J.open(e);try{const a=(await i.stat()).size,u=Math.max(f,Math.floor(a/r)),c=Buffer.allocUnsafe(t),o=[];let s=0;for(let _=u;_=0&&Ee.length&&(e=G(e,a+S)),e[g]+=S,e[i]=a,e[a]=e[q]),i=a}return[e,i]}function Z(e=0,r=fe){r=Math.max(K,r);const t=new Int32Array(new SharedArrayBuffer(r<<2));return t[g]=K,t[q]=e,t}function G(e,r=0){const t=e[g];r=Math.max(r,Math.ceil(t*le));const f=new Int32Array(new SharedArrayBuffer(r<<2));for(let i=0;ie[o].length&&(e[o]=G(e[o],n+H),i.add(o)),e[o][g]+=H,e[o][s]=n,e[o][n]=w,e[o][n+O]=R;else{const l=e[o][n];o!==l&&(n=e[o][n+O]),a.push([l,n,w,R])}}s+=D,I+=D}}a.splice(0,u)}while(a.length>0);return Array.from(i)}function ye(e,r,t,f,i="",a){const u=new Array(r.length+1);u[0]=[t,N+y,0];let c=0,o=!1;do{let[s,_,I]=u[c];if(I>=B){--c;continue}u[c][1]+=D,++u[c][2];let E=e[s][_];if(E===h)continue;const T=e[s][E];s!==T&&(E=e[s][E+O],s=T),r[c]=I+v,u[++c]=[s,E+y,0];const R=e[s][E+m];R!==h&&(o&&f.write(i),o=!0,a(f,r,c,R))}while(c>=0)}function Ne(e){const r=new Q.Worker(e);return r.on("error",t=>{throw t}),r.on("messageerror",t=>{throw t}),r.on("exit",t=>{if(t>1||t<0)throw new Error(`Worker ${r.threadId} exited with code ${t}`)}),r}function Y(e,r){return new Promise(t=>{e.once("message",t),e.postMessage(r)})}async function pe(e,r,t,f=""){t=F(t,se,ie);const i=await ue(e,t,P,ae);t=i.length;const a=new SharedArrayBuffer(x*t+1<<4),u=new Int16Array(a),c=new Int16Array(a,2),o=new Uint32Array(a,4),s=new Float64Array(a,8),_=new Array(t),I=[],E=new Array(t);for(let n=0;n{const M=d.id;for(_[d.id]=d.trie;I.length>0;){const A=await Y(l,{type:"merge",a:M,b:I.pop(),counts:o,maxes:c,mins:u,sums:s,tries:_});for(const L of A.ids)_[L]=A.tries[L]}return I.push(M),l.terminate()})}await Promise.all(E);const T=X.createWriteStream(f,{fd:f.length<1?1:void 0,flags:"a",highWaterMark:ne}),R=Buffer.allocUnsafe(ee);T.write("{"),ye(_,R,I[0],T,", ",w),T.end(`} -`);function w(n,l,d,M){const A=Math.round(s[M<<1]/o[M<<2]);n.write(l.toString("utf8",0,d)),n.write("="),n.write((u[M<<3]/10).toFixed(1)),n.write("/"),n.write((A/10).toFixed(1)),n.write("/"),n.write((c[M<<3]/10).toFixed(1))}}const $=11*k,V=111*k;function De(e,r,t){return e[r]===_e?(++r,r+4>t?$-10*e[r]-e[r+2]:V-100*e[r]-10*e[r+1]-e[r+3]):r+4>t?10*e[r]+e[r+2]-$:100*e[r]+10*e[r+1]+e[r+3]-V}async function Oe({end:e,filePath:r,id:t,start:f,counts:i,maxes:a,mins:u,sums:c}){if(f>=e)return{id:t,trie:Z(t,0)};let o=Z(t),s=t*x+1;const _=Buffer.allocUnsafe(P),I=X.createReadStream(r,{start:f,end:e-1,highWaterMark:Ee(e-f)});let E=0,T;for await(const n of I){const l=n.length;for(let d=0;d=l?a[n]:l,++i[n>>1],c[n>>2]+=l}return{id:t,trie:o}}function Se({a:e,b:r,tries:t,counts:f,maxes:i,mins:a,sums:u}){function c(o,s){o<<=3,s<<=3,a[o]=Math.min(a[o],a[s]),i[o]=Math.max(i[o],i[s]),f[o>>1]+=f[s>>1],u[o>>2]+=u[s>>2]}return{ids:ge(t,e,r,c),tries:t}}if(p.isMainThread){const e=z.fileURLToPath(typeof document>"u"?require("url").pathToFileURL(__filename).href:U&&U.src||new URL("index.cjs",document.baseURI).href);pe(process.argv[2],e,j.availableParallelism())}else p.parentPort.addListener("message",async e=>{if(e.type==="process")p.parentPort.postMessage(await Oe(e));else if(e.type==="merge")p.parentPort.postMessage(Se(e));else throw new Error("Unknown message type")}); -//# sourceMappingURL=index.cjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.cjs.map b/src/main/nodejs/havelessbemore/dist/index.cjs.map deleted file mode 100644 index b07b308..0000000 --- a/src/main/nodejs/havelessbemore/dist/index.cjs.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.cjs","sources":["../src/constants/constraints.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/constants/utf8.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/utils/parse.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n *\n * @remarks\n *\n * Changing this value affects the `count` and\n * `sum` values used for calculating a station's\n * average temperature.\n *\n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n *\n * @remarks\n *\n * Changing this value affects the `min`, `max` and `sum` values\n * used for calculating a station's min, max and avg\n * temperatures, respectively.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n *\n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n *\n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n *\n * @remarks\n *\n * This limit should be sufficient for most use cases.\n * However, feel free to adjust up or down as needed.\n *\n * There is not much basis for the current value.\n * Development was done with at most 8 workers and\n * a reasonable input file, with memory never exceeding\n * 20 MiB total across all workers.\n *\n * In theory, the challenge constraints allow for input\n * files that would require each worker using upwards of\n * 800 MiB; 10K stations with completely unique 100 byte names,\n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = trie[index /*+ TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index /*+ TRIE_PTR_IDX_IDX*/] = child;\n // Initialize node\n trie[child /* + TRIE_NODE_ID_IDX*/] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr /* + TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child /* + TRIE_NODE_ID_IDX*/];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi /* + TRIE_PTR_IDX_IDX*/];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri /*+ TRIE_NODE_ID_IDX*/];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai /*+ TRIE_PTR_IDX_IDX*/];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai /*+ TRIE_PTR_IDX_IDX*/] = li;\n // Initialize redirect\n tries[at][li /* + TRIE_XPTR_ID_IDX*/] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li /* + TRIE_NODE_ID_IDX*/];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr /* + TRIE_PTR_IDX_IDX*/];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI /* + TRIE_NODE_ID_IDX*/];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: \"process\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[res.id] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: \"merge\",\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { CHAR_MINUS, CHAR_ZERO } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CHAR_MINUS);\n b[min + ~sign] = CHAR_ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CHAR_MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { parseDouble } from \"./utils/parse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CHAR_NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 4;\n if (buffer[semI - 2] === CHAR_SEMICOLON) {\n semI -= 2;\n } else if (buffer[semI - 1] === CHAR_SEMICOLON) {\n semI -= 1;\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Request } from \"./types/request\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === \"process\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","MIN_WORKERS","MAX_WORKERS","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","unmerged","tasks","a","out","createWriteStream","printStation","name","nameLen","vi","avg","CHAR_ZERO_11","CHAR_ZERO_111","parseDouble","b","stations","createReadStream","bufI","leaf","chunk","N","semI","tempV","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","_documentCurrentScript","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index 022b3ce..64fa339 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -1,29 +1,444 @@ -/*! - * https://github.com/havelessbemore/1brc-nodejs - * - * MIT License - * - * Copyright (C) 2024-2024 Michael Rojas (https://github.com/havelessbemore) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import{availableParallelism as V}from"node:os";import{fileURLToPath as z}from"node:url";import{isMainThread as j,parentPort as S}from"node:worker_threads";import{createWriteStream as q,createReadStream as J}from"node:fs";import{open as Q}from"fs/promises";import{Worker as tt}from"worker_threads";const L=1e4,et=100,x=107,rt=16384,nt=1048576,ot=1048576,at=152e-6,st=16384,it=1,_t=512,ct=45,U=10,W=59,P=48,C=32,Et=216;function F(t,r,e){return t>r?t<=e?t:e:r}async function ft(t,r,e,u=0){const i=await Q(t);try{const a=(await i.stat()).size,E=Math.max(u,Math.floor(a/r)),c=Buffer.allocUnsafe(e),o=[];let s=0;for(let _=E;_=0&&ft.length&&(t=G(t,a+O)),t[g]+=O,t[i]=a,t[a]=t[K]),i=a}return[t,i]}function b(t=0,r=It){r=Math.max(Z,r);const e=new Int32Array(new SharedArrayBuffer(r<<2));return e[g]=Z,e[K]=t,e}function G(t,r=0){const e=t[g];r=Math.max(r,Math.ceil(e*lt));const u=new Int32Array(new SharedArrayBuffer(r<<2));for(let i=0;it[o].length&&(t[o]=G(t[o],n+H),i.add(o)),t[o][g]+=H,t[o][s]=n,t[o][n]=w,t[o][n+D]=R;else{const I=t[o][n];o!==I&&(n=t[o][n+D]),a.push([I,n,w,R])}}s+=y,l+=y}}a.splice(0,E)}while(a.length>0);return Array.from(i)}function pt(t,r,e,u,i="",a){const E=new Array(r.length+1);E[0]=[e,p+N,0];let c=0,o=!1;do{let[s,_,l]=E[c];if(l>=k){--c;continue}E[c][1]+=y,++E[c][2];let f=t[s][_];if(f===h)continue;const T=t[s][f];s!==T&&(f=t[s][f+D],s=T),r[c]=l+C,E[++c]=[s,f+N,0];const R=t[s][f+d];R!==h&&(o&&u.write(i),o=!0,a(u,r,c,R))}while(c>=0)}function yt(t){const r=new tt(t);return r.on("error",e=>{throw e}),r.on("messageerror",e=>{throw e}),r.on("exit",e=>{if(e>1||e<0)throw new Error(`Worker ${r.threadId} exited with code ${e}`)}),r}function v(t,r){return new Promise(e=>{t.once("message",e),t.postMessage(r)})}async function Dt(t,r,e,u=""){e=F(e,it,_t);const i=await ft(t,e,x,st);e=i.length;const a=new SharedArrayBuffer(L*e+1<<4),E=new Int16Array(a),c=new Int16Array(a,2),o=new Uint32Array(a,4),s=new Float64Array(a,8),_=new Array(e),l=[],f=new Array(e);for(let n=0;n{const M=m.id;for(_[m.id]=m.trie;l.length>0;){const A=await v(I,{type:"merge",a:M,b:l.pop(),counts:o,maxes:c,mins:E,sums:s,tries:_});for(const X of A.ids)_[X]=A.tries[X]}return l.push(M),I.terminate()})}await Promise.all(f);const T=q(u,{fd:u.length<1?1:void 0,flags:"a",highWaterMark:ot}),R=Buffer.allocUnsafe(et);T.write("{"),pt(_,R,l[0],T,", ",w),T.end(`} -`);function w(n,I,m,M){const A=Math.round(s[M<<1]/o[M<<2]);n.write(I.toString("utf8",0,m)),n.write("="),n.write((E[M<<3]/10).toFixed(1)),n.write("/"),n.write((A/10).toFixed(1)),n.write("/"),n.write((c[M<<3]/10).toFixed(1))}}const Y=11*P,$=111*P;function Ot(t,r,e){return t[r]===ct?(++r,r+4>e?Y-10*t[r]-t[r+2]:$-100*t[r]-10*t[r+1]-t[r+3]):r+4>e?10*t[r]+t[r+2]-Y:100*t[r]+10*t[r+1]+t[r+3]-$}async function St({end:t,filePath:r,id:e,start:u,counts:i,maxes:a,mins:E,sums:c}){if(u>=t)return{id:e,trie:b(e,0)};let o=b(e),s=e*L+1;const _=Buffer.allocUnsafe(x),l=J(r,{start:u,end:t-1,highWaterMark:ut(t-u)});let f=0,T;for await(const n of l){const I=n.length;for(let m=0;m=I?a[n]:I,++i[n>>1],c[n>>2]+=I}return{id:e,trie:o}}function Ht({a:t,b:r,tries:e,counts:u,maxes:i,mins:a,sums:E}){function c(o,s){o<<=3,s<<=3,a[o]=Math.min(a[o],a[s]),i[o]=Math.max(i[o],i[s]),u[o>>1]+=u[s>>1],E[o>>2]+=E[s>>2]}return{ids:Nt(e,t,r,c),tries:e}}if(j){const t=z(import.meta.url);Dt(process.argv[2],t,V())}else S.addListener("message",async t=>{if(t.type==="process")S.postMessage(await St(t));else if(t.type==="merge")S.postMessage(Ht(t));else throw new Error("Unknown message type")}); +// src/index.ts +import { availableParallelism } from "node:os"; +import { fileURLToPath } from "node:url"; +import { isMainThread, parentPort } from "node:worker_threads"; + +// src/main.ts +import { createWriteStream } from "node:fs"; + +// src/utils/stream.ts +import { open } from "fs/promises"; +function clamp(value, min, max) { + return value > min ? value <= max ? value : max : min; +} +async function getFileChunks(filePath, target, maxLineLength, minSize = 0) { + const file = await open(filePath); + try { + const size = (await file.stat()).size; + const chunkSize = Math.max(minSize, Math.floor(size / target)); + const buffer = Buffer.allocUnsafe(maxLineLength); + const chunks = []; + let start = 0; + for (let end = chunkSize; end < size; end += chunkSize) { + const res = await file.read(buffer, 0, maxLineLength, end); + const newline = buffer.indexOf(10 /* NEWLINE */); + if (newline >= 0 && newline < res.bytesRead) { + end += newline + 1; + chunks.push([start, end]); + start = end; + } + } + if (start < size) { + chunks.push([start, size]); + } + return chunks; + } finally { + await file.close(); + } +} +function getHighWaterMark(size) { + size *= 152e-6 /* HIGH_WATER_MARK_RATIO */; + size = Math.round(Math.log2(size)); + size = 2 ** size; + return clamp(size, 16384 /* HIGH_WATER_MARK_MIN */, 1048576 /* HIGH_WATER_MARK_MAX */); +} + +// src/constants/utf8Trie.ts +var TRIE_DEFAULT_SIZE = 655360; +var TRIE_GROWTH_FACTOR = 1.6180339887; +var TRIE_PTR_IDX_MEM = 1; +var TRIE_PTR_MEM = TRIE_PTR_IDX_MEM; +var TRIE_XPTR_ID_MEM = 1; +var TRIE_XPTR_IDX_IDX = 1; +var TRIE_XPTR_IDX_MEM = 1; +var TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM; +var TRIE_NODE_ID_IDX = 0; +var TRIE_NODE_ID_MEM = 1; +var TRIE_NODE_VALUE_IDX = 1; +var TRIE_NODE_VALUE_MEM = 1; +var TRIE_NODE_CHILDREN_IDX = 2; +var TRIE_NODE_CHILDREN_LEN = 216 /* BYTE_SPAN */; +var TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN; +var TRIE_NODE_MEM = TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM; +var TRIE_NULL = 0; +var TRIE_SIZE_IDX = 0; +var TRIE_SIZE_MEM = 1; +var TRIE_ROOT_IDX = 1; +var TRIE_ROOT_MEM = TRIE_NODE_MEM; +var TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX; +var TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM; + +// src/utils/utf8Trie.ts +function add(trie, key, min, max) { + let index = TRIE_ROOT_IDX; + while (min < max) { + index += TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */ + (key[min++] - 32 /* BYTE_MIN */); + let child = trie[ + index + /*+ TRIE_PTR_IDX_IDX*/ + ]; + if (child === TRIE_NULL) { + child = trie[TRIE_SIZE_IDX]; + if (child + TRIE_NODE_MEM > trie.length) { + trie = grow(trie, child + TRIE_NODE_MEM); + } + trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM; + trie[ + index + /*+ TRIE_PTR_IDX_IDX*/ + ] = child; + trie[ + child + /* + TRIE_NODE_ID_IDX*/ + ] = trie[TRIE_ID_IDX]; + } + index = child; + } + return [trie, index]; +} +function createTrie(id = 0, size = TRIE_DEFAULT_SIZE) { + size = Math.max(TRIE_MEM, size); + const trie = new Int32Array(new SharedArrayBuffer(size << 2)); + trie[TRIE_SIZE_IDX] = TRIE_MEM; + trie[TRIE_ID_IDX] = id; + return trie; +} +function grow(trie, minSize = 0) { + const length = trie[TRIE_SIZE_IDX]; + minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR)); + const next = new Int32Array(new SharedArrayBuffer(minSize << 2)); + for (let i = 0; i < length; ++i) { + next[i] = trie[i]; + } + return next; +} +function mergeLeft(tries, at, bt, mergeFn) { + const grown = /* @__PURE__ */ new Set(); + const queue = [ + [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX] + ]; + do { + const Q = queue.length; + for (let q = 0; q < Q; ++q) { + let [at2, ai, bt2, bi] = queue[q]; + const bvi = tries[bt2][bi + TRIE_NODE_VALUE_IDX]; + if (bvi !== TRIE_NULL) { + const avi = tries[at2][ai + TRIE_NODE_VALUE_IDX]; + if (avi !== TRIE_NULL) { + mergeFn(avi, bvi); + } else { + tries[at2][ai + TRIE_NODE_VALUE_IDX] = bvi; + } + } + ai += TRIE_NODE_CHILDREN_IDX; + bi += TRIE_NODE_CHILDREN_IDX; + const bn = bi + TRIE_NODE_CHILDREN_MEM; + while (bi < bn) { + let ri = tries[bt2][ + bi + /* + TRIE_PTR_IDX_IDX*/ + ]; + if (ri !== TRIE_NULL) { + const rt = tries[bt2][ + ri + /*+ TRIE_NODE_ID_IDX*/ + ]; + if (bt2 !== rt) { + ri = tries[bt2][ri + TRIE_XPTR_IDX_IDX]; + } + let li = tries[at2][ + ai + /*+ TRIE_PTR_IDX_IDX*/ + ]; + if (li === TRIE_NULL) { + li = tries[at2][TRIE_SIZE_IDX]; + if (li + TRIE_XPTR_MEM > tries[at2].length) { + tries[at2] = grow(tries[at2], li + TRIE_XPTR_MEM); + grown.add(at2); + } + tries[at2][TRIE_SIZE_IDX] += TRIE_XPTR_MEM; + tries[at2][ + ai + /*+ TRIE_PTR_IDX_IDX*/ + ] = li; + tries[at2][ + li + /* + TRIE_XPTR_ID_IDX*/ + ] = rt; + tries[at2][li + TRIE_XPTR_IDX_IDX] = ri; + } else { + const lt = tries[at2][ + li + /* + TRIE_NODE_ID_IDX*/ + ]; + if (at2 !== lt) { + li = tries[at2][li + TRIE_XPTR_IDX_IDX]; + } + queue.push([lt, li, rt, ri]); + } + } + ai += TRIE_PTR_MEM; + bi += TRIE_PTR_MEM; + } + } + queue.splice(0, Q); + } while (queue.length > 0); + return Array.from(grown); +} +function print(tries, key, trieIndex, stream, separator = "", callbackFn) { + const stack = new Array(key.length + 1); + stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0]; + let top = 0; + let tail = false; + do { + let [trieI, childPtr, numChild] = stack[top]; + if (numChild >= TRIE_NODE_CHILDREN_LEN) { + --top; + continue; + } + stack[top][1] += TRIE_PTR_MEM; + ++stack[top][2]; + let childI = tries[trieI][ + childPtr + /* + TRIE_PTR_IDX_IDX*/ + ]; + if (childI === TRIE_NULL) { + continue; + } + const childTrieI = tries[trieI][ + childI + /* + TRIE_NODE_ID_IDX*/ + ]; + if (trieI !== childTrieI) { + childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX]; + trieI = childTrieI; + } + key[top] = numChild + 32 /* BYTE_MIN */; + stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0]; + const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX]; + if (valueIndex !== TRIE_NULL) { + if (tail) { + stream.write(separator); + } + tail = true; + callbackFn(stream, key, top, valueIndex); + } + } while (top >= 0); +} + +// src/utils/worker.ts +import { Worker } from "worker_threads"; +function createWorker(workerPath) { + const worker = new Worker(workerPath); + worker.on("error", (err) => { + throw err; + }); + worker.on("messageerror", (err) => { + throw err; + }); + worker.on("exit", (code) => { + if (code > 1 || code < 0) { + throw new Error(`Worker ${worker.threadId} exited with code ${code}`); + } + }); + return worker; +} +function exec(worker, req) { + return new Promise((resolve) => { + worker.once("message", resolve); + worker.postMessage(req); + }); +} + +// src/main.ts +async function run(filePath, workerPath, maxWorkers, outPath = "") { + maxWorkers = clamp(maxWorkers, 1 /* WORKERS_MIN */, 512 /* WORKERS_MAX */); + const chunks = await getFileChunks( + filePath, + maxWorkers, + 107 /* MAX_ENTRY_LEN */, + 16384 /* CHUNK_SIZE_MIN */ + ); + maxWorkers = chunks.length; + const valBuf = new SharedArrayBuffer( + 1e4 /* MAX_STATIONS */ * maxWorkers + 1 << 4 + ); + const mins = new Int16Array(valBuf); + const maxes = new Int16Array(valBuf, 2); + const counts = new Uint32Array(valBuf, 4); + const sums = new Float64Array(valBuf, 8); + const tries = new Array(maxWorkers); + const unmerged = []; + const tasks = new Array(maxWorkers); + for (let i = 0; i < maxWorkers; ++i) { + const worker = createWorker(workerPath); + tasks[i] = exec(worker, { + type: "process", + counts, + end: chunks[i][1], + filePath, + id: i, + maxes, + mins, + start: chunks[i][0], + sums + }).then(async (res) => { + const a = res.id; + tries[res.id] = res.trie; + while (unmerged.length > 0) { + const res2 = await exec(worker, { + type: "merge", + a, + b: unmerged.pop(), + counts, + maxes, + mins, + sums, + tries + }); + for (const id of res2.ids) { + tries[id] = res2.tries[id]; + } + } + unmerged.push(a); + return worker.terminate(); + }); + } + await Promise.all(tasks); + const out = createWriteStream(outPath, { + fd: outPath.length < 1 ? 1 : void 0, + flags: "a", + highWaterMark: 1048576 /* HIGH_WATER_MARK_OUT */ + }); + const buffer = Buffer.allocUnsafe(100 /* MAX_STATION_NAME_LEN */); + out.write("{"); + print(tries, buffer, unmerged[0], out, ", ", printStation); + out.end("}\n"); + function printStation(stream, name, nameLen, vi) { + const avg = Math.round(sums[vi << 1] / counts[vi << 2]); + stream.write(name.toString("utf8", 0, nameLen)); + stream.write("="); + stream.write((mins[vi << 3] / 10).toFixed(1)); + stream.write("/"); + stream.write((avg / 10).toFixed(1)); + stream.write("/"); + stream.write((maxes[vi << 3] / 10).toFixed(1)); + } +} + +// src/worker.ts +import { createReadStream } from "node:fs"; + +// src/utils/parse.ts +var CHAR_ZERO_11 = 11 * 48 /* ZERO */; +var CHAR_ZERO_111 = 111 * 48 /* ZERO */; +function parseDouble(b, min, max) { + if (b[min] === 45 /* MINUS */) { + ++min; + return min + 4 > max ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2] : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3]; + } + return min + 4 > max ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11 : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111; +} + +// src/worker.ts +async function run2({ + end, + filePath, + id, + start, + // Shared memory + counts, + maxes, + mins, + sums +}) { + if (start >= end) { + return { id, trie: createTrie(id, 0) }; + } + let trie = createTrie(id); + let stations = id * 1e4 /* MAX_STATIONS */ + 1; + const buffer = Buffer.allocUnsafe(107 /* MAX_ENTRY_LEN */); + const stream = createReadStream(filePath, { + start, + end: end - 1, + highWaterMark: getHighWaterMark(end - start) + }); + let bufI = 0; + let leaf; + for await (const chunk of stream) { + const N = chunk.length; + for (let i = 0; i < N; ++i) { + if (chunk[i] !== 10 /* NEWLINE */) { + buffer[bufI++] = chunk[i]; + continue; + } + let semI = bufI - 4; + if (buffer[semI - 2] === 59 /* SEMICOLON */) { + semI -= 2; + } else if (buffer[semI - 1] === 59 /* SEMICOLON */) { + semI -= 1; + } + const tempV = parseDouble(buffer, semI + 1, bufI); + bufI = 0; + [trie, leaf] = add(trie, buffer, 0, semI); + if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) { + updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV); + } else { + trie[leaf + TRIE_NODE_VALUE_IDX] = stations; + newStation(stations++, tempV); + } + } + } + function newStation(index, temp) { + mins[index << 3] = temp; + maxes[index << 3] = temp; + counts[index << 2] = 1; + sums[index << 1] = temp; + } + function updateStation(index, temp) { + index <<= 3; + mins[index] = mins[index] <= temp ? mins[index] : temp; + maxes[index] = maxes[index] >= temp ? maxes[index] : temp; + ++counts[index >> 1]; + sums[index >> 2] += temp; + } + return { id, trie }; +} +function merge({ + a, + b, + tries, + counts, + maxes, + mins, + sums +}) { + function mergeStations(ai, bi) { + ai <<= 3; + bi <<= 3; + mins[ai] = Math.min(mins[ai], mins[bi]); + maxes[ai] = Math.max(maxes[ai], maxes[bi]); + counts[ai >> 1] += counts[bi >> 1]; + sums[ai >> 2] += sums[bi >> 2]; + } + const ids = mergeLeft(tries, a, b, mergeStations); + return { ids, tries }; +} + +// src/index.ts +if (isMainThread) { + const workerPath = fileURLToPath(import.meta.url); + run(process.argv[2], workerPath, availableParallelism()); +} else { + parentPort.addListener("message", async (msg) => { + if (msg.type === "process") { + parentPort.postMessage(await run2(msg)); + } else if (msg.type === "merge") { + parentPort.postMessage(merge(msg)); + } else { + throw new Error("Unknown message type"); + } + }); +} //# sourceMappingURL=index.mjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index 7fa3b13..3c44b95 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1 +1,7 @@ -{"version":3,"file":"index.mjs","sources":["../src/constants/constraints.ts","../src/constants/stream.ts","../src/constants/workers.ts","../src/constants/utf8.ts","../src/utils/stream.ts","../src/constants/utf8Trie.ts","../src/utils/utf8Trie.ts","../src/utils/worker.ts","../src/main.ts","../src/utils/parse.ts","../src/worker.ts","../src/index.ts"],"sourcesContent":["/**\n * The maximum number of entries.\n *\n * @remarks\n *\n * Changing this value affects the `count` and\n * `sum` values used for calculating a station's\n * average temperature.\n *\n * Valid values `v` satisfy the following constraints:\n * - Integers where `0 < v < 2^32`\n * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48\n */\nexport const MAX_ENTRIES = 1e9;\n\n/**\n * The maximum number of unique stations.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018.\n */\nexport const MAX_STATIONS = 1e4;\n\n/**\n * The maximum byte length of a station name.\n *\n * @remarks\n *\n * Changing this value affects the indexing of trie nodes.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - {@link MAX_STATIONS} * `v` < 3,314,018.\n */\nexport const STATION_NAME_MAX_LEN = 100;\n\n/**\n * The maximum byte length of a temperature reading.\n *\n * @remarks\n *\n * Changing this value affects the `min`, `max` and `sum` values\n * used for calculating a station's min, max and avg\n * temperatures, respectively.\n *\n * Valid values `v` satisfy the following constraints:\n * - Positive integer\n * - `2 <= v <= 16`.\n *\n * Please note that valid temperatures `t` should be:\n * - `-(10^(v-2)) < t < 10^(v-2)`.\n */\nexport const TEMPERATURE_MAX_LEN = 5;\n\n/**\n * The maximum length in bytes of an entry.\n *\n * Example: `Abha;71.3`\n * - Station name: 1-100 bytes\n * - Semicolon: 1 byte\n * - Temperature: 3-5 bytes\n * - Newline: 1 byte\n */\nexport const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2;\n","/**\n * The minimum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MIN = 16384; // 16KiB\n\n/**\n * The maximum value in bytes for `highWaterMark`.\n */\nexport const HIGH_WATER_MARK_MAX = 1048576; // 1MiB\n\n/**\n * The `highWaterMark` for write streams.\n */\nexport const HIGH_WATER_MARK_OUT = 1048576; // 1MiB\n\n/**\n * The ratio of the file size to use for calculating\n * the `highWaterMark` of a stream.\n */\nexport const HIGH_WATER_MARK_RATIO = 0.000152;\n\n/**\n * The minimum size in bytes of a file chunk.\n */\nexport const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN;\n","/**\n * The minimum number of web workers (inclusive).\n */\nexport const MIN_WORKERS = 1;\n\n/**\n * The maximum number of web workers (inclusive).\n *\n * The purpose is to limit the amount of memory used,\n * since each worker uses its own memory for processing.\n *\n * @remarks\n *\n * This limit should be sufficient for most use cases.\n * However, feel free to adjust up or down as needed.\n *\n * There is not much basis for the current value.\n * Development was done with at most 8 workers and\n * a reasonable input file, with memory never exceeding\n * 20 MiB total across all workers.\n *\n * In theory, the challenge constraints allow for input\n * files that would require each worker using upwards of\n * 800 MiB; 10K stations with completely unique 100 byte names,\n * thus 1M trie nodes of ~0.85 KB each. This should be\n * considered when increasing the number of workers.\n */\nexport const MAX_WORKERS = 512;\n","// UTF-8 char codes\n\n/**\n * The char code for a minus sign: -\n */\nexport const CHAR_MINUS = 45; // \"-\".charCodeAt(0);\n\n/**\n * The char code for a newline: \\n\n */\nexport const CHAR_NEWLINE = 10; // \"\\n\".charCodeAt(0);\n\n/**\n * The char code for a period: .\n */\nexport const CHAR_PERIOD = 46; // \".\".charCodeAt(0);\n\n/**\n * The char code for a semicolon: ;\n */\nexport const CHAR_SEMICOLON = 59; // \";\".charCodeAt(0);\n\n/**\n * The char code for a zero: 0\n */\nexport const CHAR_ZERO = 48; // \"0\".charCodeAt(0);\n\n// UTF-8 constants\n\n/**\n * The minimum value of a UTF-8 byte.\n *\n * Ignores C0 control codes from U+0000 to U+001F.\n *\n * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes}\n */\nexport const UTF8_BYTE_MIN = 32;\n\n/**\n * The maximum value of a UTF-8 byte.\n *\n * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding}\n */\nexport const UTF8_BYTE_MAX = 0b11110111;\n\n/**\n * The number of possible values in a UTF-8 byte.\n */\nexport const UTF8_BYTE_SPAN = UTF8_BYTE_MAX - UTF8_BYTE_MIN + 1;\n\n/*\nexport const UTF8_B0_1B_LEAD = 0b00000000;\nexport const UTF8_BN_LEAD = 0b10000000;\nexport const UTF8_B0_2B_LEAD = 0b11000000;\nexport const UTF8_B0_3B_LEAD = 0b11100000;\nexport const UTF8_B0_4B_LEAD = 0b11110000;\n\nexport const UTF8_B0_1B_LEAD_MASK = 0b10000000;\nexport const UTF8_BN_LEAD_MASK = 0b11000000;\nexport const UTF8_B0_2B_LEAD_MASK = 0b11100000;\nexport const UTF8_B0_3B_LEAD_MASK = 0b11110000;\nexport const UTF8_B0_4B_LEAD_MASK = 0b11111000;\n\nexport const UTF8_B0_1B_MAX = 0b01111111;\nexport const UTF8_BN_MAX = 0b10111111;\nexport const UTF8_B0_2B_MAX = 0b11011111;\nexport const UTF8_B0_3B_MAX = 0b11101111;\nexport const UTF8_B0_4B_MAX = 0b11110111;\n*/\n","import { open } from \"fs/promises\";\n\nimport { CHAR_NEWLINE } from \"../constants/utf8\";\nimport {\n HIGH_WATER_MARK_MAX,\n HIGH_WATER_MARK_MIN,\n HIGH_WATER_MARK_RATIO,\n} from \"../constants/stream\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CHAR_NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX);\n}\n","import { UTF8_BYTE_SPAN } from \"./utf8\";\n\n// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8_BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n","import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8_BYTE_MIN } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = trie[index /*+ TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index /*+ TRIE_PTR_IDX_IDX*/] = child;\n // Initialize node\n trie[child /* + TRIE_NODE_ID_IDX*/] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n /*TRIE_PTR_MEM * */ (key[min++] - UTF8_BYTE_MIN);\n let child = tries[trie][ptr /* + TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child /* + TRIE_NODE_ID_IDX*/];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi /* + TRIE_PTR_IDX_IDX*/];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri /*+ TRIE_NODE_ID_IDX*/];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai /*+ TRIE_PTR_IDX_IDX*/];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai /*+ TRIE_PTR_IDX_IDX*/] = li;\n // Initialize redirect\n tries[at][li /* + TRIE_XPTR_ID_IDX*/] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li /* + TRIE_NODE_ID_IDX*/];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr /* + TRIE_PTR_IDX_IDX*/];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI /* + TRIE_NODE_ID_IDX*/];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8_BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n","import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n","import { WriteStream, createWriteStream } from \"node:fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport {\n ENTRY_MAX_LEN,\n MAX_STATIONS,\n STATION_NAME_MAX_LEN,\n} from \"./constants/constraints\";\nimport { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from \"./constants/stream\";\nimport { MAX_WORKERS, MIN_WORKERS } from \"./constants/workers\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n ENTRY_MAX_LEN,\n CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: \"process\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[res.id] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: \"merge\",\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n","import { CHAR_MINUS, CHAR_ZERO } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CHAR_ZERO;\nexport const CHAR_ZERO_111 = 111 * CHAR_ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CHAR_MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CHAR_MINUS);\n b[min + ~sign] = CHAR_ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CHAR_MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n","import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { CHAR_SEMICOLON } from \"./constants/utf8\";\nimport { CHAR_NEWLINE } from \"./constants/utf8\";\nimport { ENTRY_MAX_LEN, MAX_STATIONS } from \"./constants/constraints\";\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { parseDouble } from \"./utils/parse\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CHAR_NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 4;\n if (buffer[semI - 2] === CHAR_SEMICOLON) {\n semI -= 2;\n } else if (buffer[semI - 1] === CHAR_SEMICOLON) {\n semI -= 1;\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n","import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Request } from \"./types/request\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === \"process\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n"],"names":["MAX_STATIONS","STATION_NAME_MAX_LEN","ENTRY_MAX_LEN","HIGH_WATER_MARK_MIN","HIGH_WATER_MARK_MAX","HIGH_WATER_MARK_OUT","HIGH_WATER_MARK_RATIO","CHUNK_SIZE_MIN","MIN_WORKERS","MAX_WORKERS","CHAR_MINUS","CHAR_NEWLINE","CHAR_SEMICOLON","CHAR_ZERO","UTF8_BYTE_MIN","UTF8_BYTE_SPAN","clamp","value","min","max","getFileChunks","filePath","target","maxLineLength","minSize","file","open","size","chunkSize","buffer","chunks","start","end","res","newline","getHighWaterMark","TRIE_DEFAULT_SIZE","TRIE_GROWTH_FACTOR","TRIE_PTR_IDX_MEM","TRIE_PTR_MEM","TRIE_XPTR_ID_MEM","TRIE_XPTR_IDX_IDX","TRIE_XPTR_IDX_MEM","TRIE_XPTR_MEM","TRIE_NODE_ID_IDX","TRIE_NODE_ID_MEM","TRIE_NODE_VALUE_IDX","TRIE_NODE_VALUE_MEM","TRIE_NODE_CHILDREN_IDX","TRIE_NODE_CHILDREN_LEN","TRIE_NODE_CHILDREN_MEM","TRIE_NODE_MEM","TRIE_NULL","TRIE_SIZE_IDX","TRIE_SIZE_MEM","TRIE_ROOT_IDX","TRIE_ROOT_MEM","TRIE_ID_IDX","TRIE_MEM","add","trie","key","index","child","grow","createTrie","id","length","next","i","mergeLeft","tries","at","bt","mergeFn","grown","queue","Q","q","ai","bi","bvi","avi","bn","ri","rt","li","lt","print","trieIndex","stream","separator","callbackFn","stack","top","tail","trieI","childPtr","numChild","childI","childTrieI","valueIndex","createWorker","workerPath","worker","Worker","err","code","exec","req","resolve","run","maxWorkers","outPath","valBuf","mins","maxes","counts","sums","unmerged","tasks","a","out","createWriteStream","printStation","name","nameLen","vi","avg","CHAR_ZERO_11","CHAR_ZERO_111","parseDouble","b","stations","createReadStream","bufI","leaf","chunk","N","semI","tempV","updateStation","newStation","temp","merge","mergeStations","isMainThread","fileURLToPath","runMain","availableParallelism","parentPort","msg","runWorker"],"mappings":"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"} \ No newline at end of file +{ + "version": 3, + "sources": ["../src/index.ts", "../src/main.ts", "../src/utils/stream.ts", "../src/constants/utf8Trie.ts", "../src/utils/utf8Trie.ts", "../src/utils/worker.ts", "../src/worker.ts", "../src/utils/parse.ts"], + "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Request } from \"./types/request\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === \"process\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { WriteStream, createWriteStream } from \"node:fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n BRC.MAX_ENTRY_LEN,\n Config.CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: \"process\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[res.id] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: \"merge\",\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { open } from \"fs/promises\";\n\nimport { CharCode } from \"../constants/utf8\";\nimport { Config } from \"../constants/config\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CharCode.NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= Config.HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, Config.HIGH_WATER_MARK_MIN, Config.HIGH_WATER_MARK_MAX);\n}\n", "// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\nimport { UTF8 } from \"./utf8\";\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8.BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n", "import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8 } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */ (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index /*+ TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index /*+ TRIE_PTR_IDX_IDX*/] = child;\n // Initialize node\n trie[child /* + TRIE_NODE_ID_IDX*/] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n /*TRIE_PTR_MEM * */ (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr /* + TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child /* + TRIE_NODE_ID_IDX*/];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi /* + TRIE_PTR_IDX_IDX*/];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri /*+ TRIE_NODE_ID_IDX*/];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai /*+ TRIE_PTR_IDX_IDX*/];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai /*+ TRIE_PTR_IDX_IDX*/] = li;\n // Initialize redirect\n tries[at][li /* + TRIE_XPTR_ID_IDX*/] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li /* + TRIE_NODE_ID_IDX*/];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr /* + TRIE_PTR_IDX_IDX*/];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI /* + TRIE_NODE_ID_IDX*/];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { parseDouble } from \"./utils/parse\";\nimport { CharCode } from \"./constants/utf8\";\nimport { BRC } from \"./constants/brc\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * BRC.MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(BRC.MAX_ENTRY_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CharCode.NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 4;\n if (buffer[semI - 2] === CharCode.SEMICOLON) {\n semI -= 2;\n } else if (buffer[semI - 1] === CharCode.SEMICOLON) {\n semI -= 1;\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], + "mappings": "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", + "names": ["at", "bt", "res", "run", "run"] +} diff --git a/src/main/nodejs/havelessbemore/src/constants/brc.ts b/src/main/nodejs/havelessbemore/src/constants/brc.ts new file mode 100644 index 0000000..74557b5 --- /dev/null +++ b/src/main/nodejs/havelessbemore/src/constants/brc.ts @@ -0,0 +1,74 @@ +/** + * Values for constraints imposed by the One Billion Row Challenge. + */ +export const enum BRC { + /** + * The maximum number of entries. + * + * @remarks + * + * Changing this value affects the `count` and + * `sum` values used for calculating a station's + * average temperature. + * + * Valid values `v` satisfy the following constraints: + * - Integers where `0 < v < 2^32` + * - log2(`v` * 10^({@link MAX_TEMPERATURE_LEN}-2)) < 48 + */ + MAX_ENTRIES = 1e9, + + /** + * The maximum number of unique stations. + * + * @remarks + * + * Changing this value affects the indexing of trie nodes. + * + * Valid values `v` satisfy the following constraints: + * - Positive integer + * - `v` * {@link MAX_STATION_NAME_LEN} < 3,314,018. + */ + MAX_STATIONS = 1e4, + + /** + * The maximum byte length of a station name. + * + * @remarks + * + * Changing this value affects the indexing of trie nodes. + * + * Valid values `v` satisfy the following constraints: + * - Positive integer + * - {@link MAX_STATIONS} * `v` < 3,314,018. + */ + MAX_STATION_NAME_LEN = 100, + + /** + * The maximum byte length of a temperature reading. + * + * @remarks + * + * Changing this value affects the `min`, `max` and `sum` values + * used for calculating a station's min, max and avg + * temperatures, respectively. + * + * Valid values `v` satisfy the following constraints: + * - Positive integer + * - `2 <= v <= 16`. + * + * Please note that valid temperatures `t` should be: + * - `-(10^(v-2)) < t < 10^(v-2)`. + */ + MAX_TEMPERATURE_LEN = 5, + + /** + * The maximum length in bytes of an entry. + * + * Example: `Abha;71.3` + * - Station name: 1-100 bytes + * - Semicolon: 1 byte + * - Temperature: 3-5 bytes + * - Newline: 1 byte + */ + MAX_ENTRY_LEN = MAX_STATION_NAME_LEN + MAX_TEMPERATURE_LEN + 2, +} diff --git a/src/main/nodejs/havelessbemore/src/constants/config.ts b/src/main/nodejs/havelessbemore/src/constants/config.ts new file mode 100644 index 0000000..0fbdd67 --- /dev/null +++ b/src/main/nodejs/havelessbemore/src/constants/config.ts @@ -0,0 +1,56 @@ +export const enum Config { + /** + * The minimum value in bytes for `highWaterMark`. + */ + HIGH_WATER_MARK_MIN = 16384, // 16KiB + + /** + * The maximum value in bytes for `highWaterMark`. + */ + HIGH_WATER_MARK_MAX = 1048576, // 1MiB + + /** + * The `highWaterMark` for write streams. + */ + HIGH_WATER_MARK_OUT = 1048576, // 1MiB + + /** + * The ratio of the file size to use for calculating + * the `highWaterMark` of a stream. + */ + HIGH_WATER_MARK_RATIO = 0.000152, + + /** + * The minimum size in bytes of a file chunk. + */ + CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN, + + /** + * The minimum number of web workers (inclusive). + */ + WORKERS_MIN = 1, + + /** + * The maximum number of web workers (inclusive). + * + * The purpose is to limit the amount of memory used, + * since each worker uses its own memory for processing. + * + * @remarks + * + * This limit should be sufficient for most use cases. + * However, feel free to adjust up or down as needed. + * + * There is not much basis for the current value. + * Development was done with at most 8 workers and + * a reasonable input file, with memory never exceeding + * 20 MiB total across all workers. + * + * In theory, the challenge constraints allow for input + * files that would require each worker using upwards of + * 800 MiB; 10K stations with completely unique 100 byte names, + * thus 1M trie nodes of ~0.85 KB each. This should be + * considered when increasing the number of workers. + */ + WORKERS_MAX = 512, +} diff --git a/src/main/nodejs/havelessbemore/src/constants/constraints.ts b/src/main/nodejs/havelessbemore/src/constants/constraints.ts deleted file mode 100644 index 76827cb..0000000 --- a/src/main/nodejs/havelessbemore/src/constants/constraints.ts +++ /dev/null @@ -1,69 +0,0 @@ -/** - * The maximum number of entries. - * - * @remarks - * - * Changing this value affects the `count` and - * `sum` values used for calculating a station's - * average temperature. - * - * Valid values `v` satisfy the following constraints: - * - Integers where `0 < v < 2^32` - * - log2(`v` * 10^({@link TEMPERATURE_MAX_LEN}-2)) < 48 - */ -export const MAX_ENTRIES = 1e9; - -/** - * The maximum number of unique stations. - * - * @remarks - * - * Changing this value affects the indexing of trie nodes. - * - * Valid values `v` satisfy the following constraints: - * - Positive integer - * - `v` * {@link STATION_NAME_MAX_LEN} < 3,314,018. - */ -export const MAX_STATIONS = 1e4; - -/** - * The maximum byte length of a station name. - * - * @remarks - * - * Changing this value affects the indexing of trie nodes. - * - * Valid values `v` satisfy the following constraints: - * - Positive integer - * - {@link MAX_STATIONS} * `v` < 3,314,018. - */ -export const STATION_NAME_MAX_LEN = 100; - -/** - * The maximum byte length of a temperature reading. - * - * @remarks - * - * Changing this value affects the `min`, `max` and `sum` values - * used for calculating a station's min, max and avg - * temperatures, respectively. - * - * Valid values `v` satisfy the following constraints: - * - Positive integer - * - `2 <= v <= 16`. - * - * Please note that valid temperatures `t` should be: - * - `-(10^(v-2)) < t < 10^(v-2)`. - */ -export const TEMPERATURE_MAX_LEN = 5; - -/** - * The maximum length in bytes of an entry. - * - * Example: `Abha;71.3` - * - Station name: 1-100 bytes - * - Semicolon: 1 byte - * - Temperature: 3-5 bytes - * - Newline: 1 byte - */ -export const ENTRY_MAX_LEN = STATION_NAME_MAX_LEN + TEMPERATURE_MAX_LEN + 2; diff --git a/src/main/nodejs/havelessbemore/src/constants/stream.ts b/src/main/nodejs/havelessbemore/src/constants/stream.ts deleted file mode 100644 index 131b9c3..0000000 --- a/src/main/nodejs/havelessbemore/src/constants/stream.ts +++ /dev/null @@ -1,25 +0,0 @@ -/** - * The minimum value in bytes for `highWaterMark`. - */ -export const HIGH_WATER_MARK_MIN = 16384; // 16KiB - -/** - * The maximum value in bytes for `highWaterMark`. - */ -export const HIGH_WATER_MARK_MAX = 1048576; // 1MiB - -/** - * The `highWaterMark` for write streams. - */ -export const HIGH_WATER_MARK_OUT = 1048576; // 1MiB - -/** - * The ratio of the file size to use for calculating - * the `highWaterMark` of a stream. - */ -export const HIGH_WATER_MARK_RATIO = 0.000152; - -/** - * The minimum size in bytes of a file chunk. - */ -export const CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN; diff --git a/src/main/nodejs/havelessbemore/src/constants/utf8.ts b/src/main/nodejs/havelessbemore/src/constants/utf8.ts index eea7135..82ee508 100644 --- a/src/main/nodejs/havelessbemore/src/constants/utf8.ts +++ b/src/main/nodejs/havelessbemore/src/constants/utf8.ts @@ -1,56 +1,55 @@ - export const enum CharCode { - /** - * The char code for a minus sign: - - */ - MINUS = 45, // "-".charCodeAt(0), + /** + * The char code for a minus sign: - + */ + MINUS = 45, // "-".charCodeAt(0), - /** - * The char code for a newline: \n - */ - NEWLINE = 10, // "\n".charCodeAt(0), + /** + * The char code for a newline: \n + */ + NEWLINE = 10, // "\n".charCodeAt(0), - /** - * The char code for a period: . - */ - PERIOD = 46, // ".".charCodeAt(0), + /** + * The char code for a period: . + */ + PERIOD = 46, // ".".charCodeAt(0), - /** - * The char code for a semicolon: , - */ - SEMICOLON = 59, // ";".charCodeAt(0), + /** + * The char code for a semicolon: , + */ + SEMICOLON = 59, // ";".charCodeAt(0), - /** - * The char code for a zero: 0 - */ - ZERO = 48, // "0".charCodeAt(0), -}; + /** + * The char code for a zero: 0 + */ + ZERO = 48, // "0".charCodeAt(0), +} // UTF-8 constants export const enum UTF8 { - /** - * The minimum value of a UTF-8 byte. - * - * Ignores C0 control codes from U+0000 to U+001F. - * - * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes} - */ - BYTE_MIN = 32, + /** + * The minimum value of a UTF-8 byte. + * + * Ignores C0 control codes from U+0000 to U+001F. + * + * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes} + */ + BYTE_MIN = 32, - /** - * The maximum value of a UTF-8 byte. - * - * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding} - */ - BYTE_MAX = 0b11110111, + /** + * The maximum value of a UTF-8 byte. + * + * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding} + */ + BYTE_MAX = 0b11110111, - /** - * The number of possible values in a UTF-8 byte. - */ - BYTE_SPAN = BYTE_MAX - BYTE_MIN + 1, + /** + * The number of possible values in a UTF-8 byte. + */ + BYTE_SPAN = BYTE_MAX - BYTE_MIN + 1, - /* + /* B0_1B_LEAD = 0b00000000, BN_LEAD = 0b10000000, B0_2B_LEAD = 0b11000000, @@ -69,4 +68,4 @@ export const enum UTF8 { B0_3B_MAX = 0b11101111, B0_4B_MAX = 0b11110111, */ -}; +} diff --git a/src/main/nodejs/havelessbemore/src/constants/workers.ts b/src/main/nodejs/havelessbemore/src/constants/workers.ts deleted file mode 100644 index c31d359..0000000 --- a/src/main/nodejs/havelessbemore/src/constants/workers.ts +++ /dev/null @@ -1,28 +0,0 @@ -/** - * The minimum number of web workers (inclusive). - */ -export const MIN_WORKERS = 1; - -/** - * The maximum number of web workers (inclusive). - * - * The purpose is to limit the amount of memory used, - * since each worker uses its own memory for processing. - * - * @remarks - * - * This limit should be sufficient for most use cases. - * However, feel free to adjust up or down as needed. - * - * There is not much basis for the current value. - * Development was done with at most 8 workers and - * a reasonable input file, with memory never exceeding - * 20 MiB total across all workers. - * - * In theory, the challenge constraints allow for input - * files that would require each worker using upwards of - * 800 MiB; 10K stations with completely unique 100 byte names, - * thus 1M trie nodes of ~0.85 KB each. This should be - * considered when increasing the number of workers. - */ -export const MAX_WORKERS = 512; diff --git a/src/main/nodejs/havelessbemore/src/main.ts b/src/main/nodejs/havelessbemore/src/main.ts index ab9115b..7bb10e0 100644 --- a/src/main/nodejs/havelessbemore/src/main.ts +++ b/src/main/nodejs/havelessbemore/src/main.ts @@ -5,16 +5,11 @@ import type { MergeResponse } from "./types/mergeResponse"; import type { ProcessRequest } from "./types/processRequest"; import type { ProcessResponse } from "./types/processResponse"; -import { - ENTRY_MAX_LEN, - MAX_STATIONS, - STATION_NAME_MAX_LEN, -} from "./constants/constraints"; -import { CHUNK_SIZE_MIN, HIGH_WATER_MARK_OUT } from "./constants/stream"; -import { MAX_WORKERS, MIN_WORKERS } from "./constants/workers"; import { clamp, getFileChunks } from "./utils/stream"; import { print } from "./utils/utf8Trie"; import { createWorker, exec } from "./utils/worker"; +import { BRC } from "./constants/brc"; +import { Config } from "./constants/config"; export async function run( filePath: string, @@ -23,21 +18,23 @@ export async function run( outPath = "", ): Promise { // Sanitize number of workers - maxWorkers = clamp(maxWorkers, MIN_WORKERS, MAX_WORKERS); + maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX); // Split the file into chunks. Creates 1 or fewer chunks per worker const chunks = await getFileChunks( filePath, maxWorkers, - ENTRY_MAX_LEN, - CHUNK_SIZE_MIN, + BRC.MAX_ENTRY_LEN, + Config.CHUNK_SIZE_MIN, ); // Adjust the number of workers to the number of chunks maxWorkers = chunks.length; // Initialize data - const valBuf = new SharedArrayBuffer((MAX_STATIONS * maxWorkers + 1) << 4); + const valBuf = new SharedArrayBuffer( + (BRC.MAX_STATIONS * maxWorkers + 1) << 4, + ); const mins = new Int16Array(valBuf); const maxes = new Int16Array(valBuf, 2); const counts = new Uint32Array(valBuf, 4); @@ -95,9 +92,9 @@ export async function run( const out = createWriteStream(outPath, { fd: outPath.length < 1 ? 1 : undefined, flags: "a", - highWaterMark: HIGH_WATER_MARK_OUT, + highWaterMark: Config.HIGH_WATER_MARK_OUT, }); - const buffer = Buffer.allocUnsafe(STATION_NAME_MAX_LEN); + const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN); out.write("{"); print(tries, buffer, unmerged[0], out, ", ", printStation); out.end("}\n"); diff --git a/src/main/nodejs/havelessbemore/src/utils/stream.ts b/src/main/nodejs/havelessbemore/src/utils/stream.ts index 2295eaf..a2ee229 100644 --- a/src/main/nodejs/havelessbemore/src/utils/stream.ts +++ b/src/main/nodejs/havelessbemore/src/utils/stream.ts @@ -1,11 +1,7 @@ import { open } from "fs/promises"; -import { - HIGH_WATER_MARK_MAX, - HIGH_WATER_MARK_MIN, - HIGH_WATER_MARK_RATIO, -} from "../constants/stream"; import { CharCode } from "../constants/utf8"; +import { Config } from "../constants/config"; /** * Clamp a value within a given range. @@ -92,11 +88,11 @@ export async function getFileChunks( */ export function getHighWaterMark(size: number): number { // Get size percentage - size *= HIGH_WATER_MARK_RATIO; + size *= Config.HIGH_WATER_MARK_RATIO; // Get nearest power size = Math.round(Math.log2(size)); // Calculate high water mark size = 2 ** size; // Clamp value - return clamp(size, HIGH_WATER_MARK_MIN, HIGH_WATER_MARK_MAX); + return clamp(size, Config.HIGH_WATER_MARK_MIN, Config.HIGH_WATER_MARK_MAX); } diff --git a/src/main/nodejs/havelessbemore/src/worker.ts b/src/main/nodejs/havelessbemore/src/worker.ts index 1502b2c..41de611 100644 --- a/src/main/nodejs/havelessbemore/src/worker.ts +++ b/src/main/nodejs/havelessbemore/src/worker.ts @@ -3,7 +3,6 @@ import { createReadStream } from "node:fs"; import type { ProcessRequest } from "./types/processRequest"; import type { ProcessResponse } from "./types/processResponse"; -import { ENTRY_MAX_LEN, MAX_STATIONS } from "./constants/constraints"; import { TRIE_NODE_VALUE_IDX, TRIE_NULL } from "./constants/utf8Trie"; import { getHighWaterMark } from "./utils/stream"; import { add, createTrie, mergeLeft } from "./utils/utf8Trie"; @@ -11,6 +10,7 @@ import { MergeRequest } from "./types/mergeRequest"; import { MergeResponse } from "./types/mergeResponse"; import { parseDouble } from "./utils/parse"; import { CharCode } from "./constants/utf8"; +import { BRC } from "./constants/brc"; export async function run({ end, @@ -30,8 +30,8 @@ export async function run({ // Initialize constants let trie = createTrie(id); - let stations = id * MAX_STATIONS + 1; - const buffer = Buffer.allocUnsafe(ENTRY_MAX_LEN); + let stations = id * BRC.MAX_STATIONS + 1; + const buffer = Buffer.allocUnsafe(BRC.MAX_ENTRY_LEN); // Create the chunk stream const stream = createReadStream(filePath, { From 4c90e7d999687c238e70052663228d43af6aeed1 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Sat, 25 May 2024 13:37:52 -0400 Subject: [PATCH 43/69] Update utf8trie constants into const enums --- src/main/nodejs/havelessbemore/dist/index.mjs | 187 +++++++----------- .../nodejs/havelessbemore/dist/index.mjs.map | 6 +- .../havelessbemore/src/constants/utf8Trie.ts | 147 +++++++------- src/main/nodejs/havelessbemore/src/index.ts | 7 +- src/main/nodejs/havelessbemore/src/main.ts | 4 +- .../nodejs/havelessbemore/src/utils/stream.ts | 2 +- .../havelessbemore/src/utils/utf8Trie.ts | 141 +++++++------ src/main/nodejs/havelessbemore/src/worker.ts | 18 +- 8 files changed, 235 insertions(+), 277 deletions(-) diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index 64fa339..4e5b995 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -44,69 +44,56 @@ function getHighWaterMark(size) { } // src/constants/utf8Trie.ts -var TRIE_DEFAULT_SIZE = 655360; -var TRIE_GROWTH_FACTOR = 1.6180339887; -var TRIE_PTR_IDX_MEM = 1; -var TRIE_PTR_MEM = TRIE_PTR_IDX_MEM; -var TRIE_XPTR_ID_MEM = 1; -var TRIE_XPTR_IDX_IDX = 1; -var TRIE_XPTR_IDX_MEM = 1; -var TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM; -var TRIE_NODE_ID_IDX = 0; -var TRIE_NODE_ID_MEM = 1; -var TRIE_NODE_VALUE_IDX = 1; -var TRIE_NODE_VALUE_MEM = 1; -var TRIE_NODE_CHILDREN_IDX = 2; -var TRIE_NODE_CHILDREN_LEN = 216 /* BYTE_SPAN */; -var TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN; -var TRIE_NODE_MEM = TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM; -var TRIE_NULL = 0; -var TRIE_SIZE_IDX = 0; -var TRIE_SIZE_MEM = 1; -var TRIE_ROOT_IDX = 1; -var TRIE_ROOT_MEM = TRIE_NODE_MEM; -var TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX; -var TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM; +var TrieNodeProto = ((TrieNodeProto2) => { + TrieNodeProto2[TrieNodeProto2["ID_IDX"] = 0] = "ID_IDX"; + TrieNodeProto2[TrieNodeProto2["ID_MEM"] = 1] = "ID_MEM"; + TrieNodeProto2[TrieNodeProto2["VALUE_IDX"] = 1] = "VALUE_IDX"; + TrieNodeProto2[TrieNodeProto2["VALUE_MEM"] = 1] = "VALUE_MEM"; + TrieNodeProto2[TrieNodeProto2["CHILDREN_IDX"] = 2] = "CHILDREN_IDX"; + TrieNodeProto2[TrieNodeProto2["CHILDREN_LEN"] = 216 /* BYTE_SPAN */] = "CHILDREN_LEN"; + TrieNodeProto2[TrieNodeProto2["CHILDREN_MEM"] = 1 /* MEM */ * TrieNodeProto2.CHILDREN_LEN] = "CHILDREN_MEM"; + TrieNodeProto2[TrieNodeProto2["MEM"] = 2 + TrieNodeProto2.CHILDREN_MEM] = "MEM"; + return TrieNodeProto2; +})(TrieNodeProto || {}); +var TrieProto = ((TrieProto2) => { + TrieProto2[TrieProto2["SIZE_IDX"] = 0] = "SIZE_IDX"; + TrieProto2[TrieProto2["SIZE_MEM"] = 1] = "SIZE_MEM"; + TrieProto2[TrieProto2["ROOT_IDX"] = 1] = "ROOT_IDX"; + TrieProto2[TrieProto2["ROOT_MEM"] = TrieNodeProto.MEM] = "ROOT_MEM"; + TrieProto2[TrieProto2["ID_IDX"] = 1] = "ID_IDX"; + TrieProto2[TrieProto2["MEM"] = 1 /* SIZE_MEM */ + TrieProto2.ROOT_MEM] = "MEM"; + return TrieProto2; +})(TrieProto || {}); // src/utils/utf8Trie.ts function add(trie, key, min, max) { - let index = TRIE_ROOT_IDX; + let index = 1 /* ROOT_IDX */; while (min < max) { - index += TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */ - (key[min++] - 32 /* BYTE_MIN */); - let child = trie[ - index - /*+ TRIE_PTR_IDX_IDX*/ - ]; - if (child === TRIE_NULL) { - child = trie[TRIE_SIZE_IDX]; - if (child + TRIE_NODE_MEM > trie.length) { - trie = grow(trie, child + TRIE_NODE_MEM); + index += 2 /* CHILDREN_IDX */ + 1 /* MEM */ * (key[min++] - 32 /* BYTE_MIN */); + let child = trie[index + 0 /* IDX_IDX */]; + if (child === 0 /* NULL */) { + child = trie[0 /* SIZE_IDX */]; + if (child + TrieNodeProto.MEM > trie.length) { + trie = grow(trie, child + TrieNodeProto.MEM); } - trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM; - trie[ - index - /*+ TRIE_PTR_IDX_IDX*/ - ] = child; - trie[ - child - /* + TRIE_NODE_ID_IDX*/ - ] = trie[TRIE_ID_IDX]; + trie[0 /* SIZE_IDX */] += TrieNodeProto.MEM; + trie[index + 0 /* IDX_IDX */] = child; + trie[child + 0 /* ID_IDX */] = trie[1 /* ID_IDX */]; } index = child; } return [trie, index]; } -function createTrie(id = 0, size = TRIE_DEFAULT_SIZE) { - size = Math.max(TRIE_MEM, size); +function createTrie(id = 0, size = 655360 /* DEFAULT_SIZE */) { + size = Math.max(TrieProto.MEM, size); const trie = new Int32Array(new SharedArrayBuffer(size << 2)); - trie[TRIE_SIZE_IDX] = TRIE_MEM; - trie[TRIE_ID_IDX] = id; + trie[0 /* SIZE_IDX */] = TrieProto.MEM; + trie[1 /* ID_IDX */] = id; return trie; } function grow(trie, minSize = 0) { - const length = trie[TRIE_SIZE_IDX]; - minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR)); + const length = trie[0 /* SIZE_IDX */]; + minSize = Math.max(minSize, Math.ceil(length * 1.6180339887 /* GROWTH_FACTOR */)); const next = new Int32Array(new SharedArrayBuffer(minSize << 2)); for (let i = 0; i < length; ++i) { next[i] = trie[i]; @@ -116,70 +103,52 @@ function grow(trie, minSize = 0) { function mergeLeft(tries, at, bt, mergeFn) { const grown = /* @__PURE__ */ new Set(); const queue = [ - [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX] + [at, 1 /* ROOT_IDX */, bt, 1 /* ROOT_IDX */] ]; do { const Q = queue.length; for (let q = 0; q < Q; ++q) { let [at2, ai, bt2, bi] = queue[q]; - const bvi = tries[bt2][bi + TRIE_NODE_VALUE_IDX]; - if (bvi !== TRIE_NULL) { - const avi = tries[at2][ai + TRIE_NODE_VALUE_IDX]; - if (avi !== TRIE_NULL) { + const bvi = tries[bt2][bi + 1 /* VALUE_IDX */]; + if (bvi !== 0 /* NULL */) { + const avi = tries[at2][ai + 1 /* VALUE_IDX */]; + if (avi !== 0 /* NULL */) { mergeFn(avi, bvi); } else { - tries[at2][ai + TRIE_NODE_VALUE_IDX] = bvi; + tries[at2][ai + 1 /* VALUE_IDX */] = bvi; } } - ai += TRIE_NODE_CHILDREN_IDX; - bi += TRIE_NODE_CHILDREN_IDX; - const bn = bi + TRIE_NODE_CHILDREN_MEM; + ai += 2 /* CHILDREN_IDX */; + bi += 2 /* CHILDREN_IDX */; + const bn = bi + TrieNodeProto.CHILDREN_MEM; while (bi < bn) { - let ri = tries[bt2][ - bi - /* + TRIE_PTR_IDX_IDX*/ - ]; - if (ri !== TRIE_NULL) { - const rt = tries[bt2][ - ri - /*+ TRIE_NODE_ID_IDX*/ - ]; + let ri = tries[bt2][bi + 0 /* IDX_IDX */]; + if (ri !== 0 /* NULL */) { + const rt = tries[bt2][ri + 0 /* ID_IDX */]; if (bt2 !== rt) { - ri = tries[bt2][ri + TRIE_XPTR_IDX_IDX]; + ri = tries[bt2][ri + 1 /* IDX_IDX */]; } - let li = tries[at2][ - ai - /*+ TRIE_PTR_IDX_IDX*/ - ]; - if (li === TRIE_NULL) { - li = tries[at2][TRIE_SIZE_IDX]; - if (li + TRIE_XPTR_MEM > tries[at2].length) { - tries[at2] = grow(tries[at2], li + TRIE_XPTR_MEM); + let li = tries[at2][ai + 0 /* IDX_IDX */]; + if (li === 0 /* NULL */) { + li = tries[at2][0 /* SIZE_IDX */]; + if (li + 2 /* MEM */ > tries[at2].length) { + tries[at2] = grow(tries[at2], li + 2 /* MEM */); grown.add(at2); } - tries[at2][TRIE_SIZE_IDX] += TRIE_XPTR_MEM; - tries[at2][ - ai - /*+ TRIE_PTR_IDX_IDX*/ - ] = li; - tries[at2][ - li - /* + TRIE_XPTR_ID_IDX*/ - ] = rt; - tries[at2][li + TRIE_XPTR_IDX_IDX] = ri; + tries[at2][0 /* SIZE_IDX */] += 2 /* MEM */; + tries[at2][ai + 0 /* IDX_IDX */] = li; + tries[at2][li + 0 /* ID_IDX */] = rt; + tries[at2][li + 1 /* IDX_IDX */] = ri; } else { - const lt = tries[at2][ - li - /* + TRIE_NODE_ID_IDX*/ - ]; + const lt = tries[at2][li + 0 /* ID_IDX */]; if (at2 !== lt) { - li = tries[at2][li + TRIE_XPTR_IDX_IDX]; + li = tries[at2][li + 1 /* IDX_IDX */]; } queue.push([lt, li, rt, ri]); } } - ai += TRIE_PTR_MEM; - bi += TRIE_PTR_MEM; + ai += 1 /* MEM */; + bi += 1 /* MEM */; } } queue.splice(0, Q); @@ -188,36 +157,30 @@ function mergeLeft(tries, at, bt, mergeFn) { } function print(tries, key, trieIndex, stream, separator = "", callbackFn) { const stack = new Array(key.length + 1); - stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0]; + stack[0] = [trieIndex, 1 /* ROOT_IDX */ + 2 /* CHILDREN_IDX */, 0]; let top = 0; let tail = false; do { let [trieI, childPtr, numChild] = stack[top]; - if (numChild >= TRIE_NODE_CHILDREN_LEN) { + if (numChild >= TrieNodeProto.CHILDREN_LEN) { --top; continue; } - stack[top][1] += TRIE_PTR_MEM; + stack[top][1] += 1 /* MEM */; ++stack[top][2]; - let childI = tries[trieI][ - childPtr - /* + TRIE_PTR_IDX_IDX*/ - ]; - if (childI === TRIE_NULL) { + let childI = tries[trieI][childPtr + 0 /* IDX_IDX */]; + if (childI === 0 /* NULL */) { continue; } - const childTrieI = tries[trieI][ - childI - /* + TRIE_NODE_ID_IDX*/ - ]; + const childTrieI = tries[trieI][childI + 0 /* ID_IDX */]; if (trieI !== childTrieI) { - childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX]; + childI = tries[trieI][childI + 1 /* IDX_IDX */]; trieI = childTrieI; } key[top] = numChild + 32 /* BYTE_MIN */; - stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0]; - const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX]; - if (valueIndex !== TRIE_NULL) { + stack[++top] = [trieI, childI + 2 /* CHILDREN_IDX */, 0]; + const valueIndex = tries[trieI][childI + 1 /* VALUE_IDX */]; + if (valueIndex !== 0 /* NULL */) { if (tail) { stream.write(separator); } @@ -382,10 +345,10 @@ async function run2({ const tempV = parseDouble(buffer, semI + 1, bufI); bufI = 0; [trie, leaf] = add(trie, buffer, 0, semI); - if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) { - updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV); + if (trie[leaf + 1 /* VALUE_IDX */] !== 0 /* NULL */) { + updateStation(trie[leaf + 1 /* VALUE_IDX */], tempV); } else { - trie[leaf + TRIE_NODE_VALUE_IDX] = stations; + trie[leaf + 1 /* VALUE_IDX */] = stations; newStation(stations++, tempV); } } diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index 3c44b95..1a1fc8e 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../src/index.ts", "../src/main.ts", "../src/utils/stream.ts", "../src/constants/utf8Trie.ts", "../src/utils/utf8Trie.ts", "../src/utils/worker.ts", "../src/worker.ts", "../src/utils/parse.ts"], - "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\nimport { Request } from \"./types/request\";\nimport { ProcessRequest } from \"./types/processRequest\";\nimport { MergeRequest } from \"./types/mergeRequest\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === \"process\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { WriteStream, createWriteStream } from \"node:fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n BRC.MAX_ENTRY_LEN,\n Config.CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: \"process\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[res.id] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: \"merge\",\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { open } from \"fs/promises\";\n\nimport { CharCode } from \"../constants/utf8\";\nimport { Config } from \"../constants/config\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CharCode.NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= Config.HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, Config.HIGH_WATER_MARK_MIN, Config.HIGH_WATER_MARK_MAX);\n}\n", "// Configurable constants.\n//\n// Controls trie behavior such as the default\n// allocated size and the growth factor when resizing.\n\nimport { UTF8 } from \"./utf8\";\n\n/**\n * The default initial size of a trie.\n */\nexport const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB\n\n/**\n * The growth factor for resizing a trie (Approx. Phi)\n */\nexport const TRIE_GROWTH_FACTOR = 1.6180339887;\n\n// Trie pointer\n//\n// A pointer can point to either a trie node or a trie redirect.\n// They can be differentiated by the destination's ID value:\n// - If the ID matches the trie's ID, then it's a trie node.\n// - Otherwise, it's a trie redirect.\n\n// The memory location the pointer points to.\nexport const TRIE_PTR_IDX_IDX = 0;\nexport const TRIE_PTR_IDX_MEM = 1;\n\nexport const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM;\n\n// Trie redirect (aka cross-trie pointer)\n//\n// Points to a memory location in a different trie.\n\n// The different trie's ID.\nexport const TRIE_XPTR_ID_IDX = 0;\nexport const TRIE_XPTR_ID_MEM = 1;\n\n// The memory location of the trie node in the different trie.\nexport const TRIE_XPTR_IDX_IDX = 1;\nexport const TRIE_XPTR_IDX_MEM = 1;\n\nexport const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM;\n\n// Trie node\n\n// The trie's ID\nexport const TRIE_NODE_ID_IDX = 0;\nexport const TRIE_NODE_ID_MEM = 1;\n\n// The node's value\nexport const TRIE_NODE_VALUE_IDX = 1;\nexport const TRIE_NODE_VALUE_MEM = 1;\n\n// The node's children pointers\nexport const TRIE_NODE_CHILDREN_IDX = 2;\nexport const TRIE_NODE_CHILDREN_LEN = UTF8.BYTE_SPAN;\nexport const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN;\n\nexport const TRIE_NODE_MEM =\n TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM;\n\n// Trie\n\n/**\n * Represents a `null` trie element.\n */\nexport const TRIE_NULL = 0;\n\n// The memory location for the trie's size.\nexport const TRIE_SIZE_IDX = 0;\nexport const TRIE_SIZE_MEM = 1;\n\n// The memory location for the trie's root node.\nexport const TRIE_ROOT_IDX = 1;\nexport const TRIE_ROOT_MEM = TRIE_NODE_MEM;\n\n// The memory location for the trie's ID (i.e. the root node's trie ID).\nexport const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX;\n\nexport const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM;\n", "import { WriteStream } from \"node:fs\";\n\nimport {\n TRIE_DEFAULT_SIZE,\n TRIE_PTR_MEM,\n TRIE_GROWTH_FACTOR,\n TRIE_MEM,\n TRIE_ID_IDX,\n TRIE_NODE_CHILDREN_IDX,\n TRIE_NODE_VALUE_IDX,\n TRIE_NULL,\n TRIE_ROOT_IDX,\n TRIE_SIZE_IDX,\n TRIE_XPTR_MEM,\n TRIE_XPTR_IDX_IDX,\n TRIE_NODE_MEM,\n TRIE_NODE_CHILDREN_MEM,\n TRIE_NODE_CHILDREN_LEN,\n} from \"../constants/utf8Trie\";\nimport { UTF8 } from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index = TRIE_ROOT_IDX;\n while (min < max) {\n index +=\n TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */ (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index /*+ TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n // Allocate node\n child = trie[TRIE_SIZE_IDX];\n if (child + TRIE_NODE_MEM > trie.length) {\n trie = grow(trie, child + TRIE_NODE_MEM);\n }\n trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM;\n // Attach node\n trie[index /*+ TRIE_PTR_IDX_IDX*/] = child;\n // Initialize node\n trie[child /* + TRIE_NODE_ID_IDX*/] = trie[TRIE_ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node = TRIE_ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TRIE_NODE_CHILDREN_IDX +\n /*TRIE_PTR_MEM * */ (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr /* + TRIE_PTR_IDX_IDX*/];\n if (child === TRIE_NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child /* + TRIE_NODE_ID_IDX*/];\n if (childTrie !== trie) {\n child = tries[trie][child + TRIE_XPTR_IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array {\n size = Math.max(TRIE_MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TRIE_SIZE_IDX] = TRIE_MEM;\n trie[TRIE_ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TRIE_SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX];\n if (bvi !== TRIE_NULL) {\n // If left value is not null\n const avi = tries[at][ai + TRIE_NODE_VALUE_IDX];\n if (avi !== TRIE_NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TRIE_NODE_CHILDREN_IDX;\n bi += TRIE_NODE_CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TRIE_NODE_CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi /* + TRIE_PTR_IDX_IDX*/];\n if (ri !== TRIE_NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri /*+ TRIE_NODE_ID_IDX*/];\n if (bt !== rt) {\n ri = tries[bt][ri + TRIE_XPTR_IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai /*+ TRIE_PTR_IDX_IDX*/];\n if (li === TRIE_NULL) {\n // Allocate redirect\n li = tries[at][TRIE_SIZE_IDX];\n if (li + TRIE_XPTR_MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TRIE_XPTR_MEM);\n grown.add(at);\n }\n tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM;\n // Attach redirect\n tries[at][ai /*+ TRIE_PTR_IDX_IDX*/] = li;\n // Initialize redirect\n tries[at][li /* + TRIE_XPTR_ID_IDX*/] = rt;\n tries[at][li + TRIE_XPTR_IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li /* + TRIE_NODE_ID_IDX*/];\n if (at !== lt) {\n li = tries[at][li + TRIE_XPTR_IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TRIE_PTR_MEM;\n bi += TRIE_PTR_MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TRIE_NODE_CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TRIE_PTR_MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr /* + TRIE_PTR_IDX_IDX*/];\n if (childI === TRIE_NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI /* + TRIE_NODE_ID_IDX*/];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX];\n if (valueIndex !== TRIE_NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { createReadStream } from \"node:fs\";\n\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { TRIE_NODE_VALUE_IDX, TRIE_NULL } from \"./constants/utf8Trie\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { MergeRequest } from \"./types/mergeRequest\";\nimport { MergeResponse } from \"./types/mergeResponse\";\nimport { parseDouble } from \"./utils/parse\";\nimport { CharCode } from \"./constants/utf8\";\nimport { BRC } from \"./constants/brc\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * BRC.MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(BRC.MAX_ENTRY_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CharCode.NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 4;\n if (buffer[semI - 2] === CharCode.SEMICOLON) {\n semI -= 2;\n } else if (buffer[semI - 1] === CharCode.SEMICOLON) {\n semI -= 1;\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) {\n // Update the station's value\n updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TRIE_NODE_VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], - "mappings": "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", - "names": ["at", "bt", "res", "run", "run"] + "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === \"process\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { WriteStream, createWriteStream } from \"node:fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n BRC.MAX_ENTRY_LEN,\n Config.CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: \"process\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[res.id] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: \"merge\",\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { open } from \"fs/promises\";\n\nimport { Config } from \"../constants/config\";\nimport { CharCode } from \"../constants/utf8\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CharCode.NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= Config.HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, Config.HIGH_WATER_MARK_MIN, Config.HIGH_WATER_MARK_MAX);\n}\n", "import { UTF8 } from \"./utf8\";\n\nexport const enum Trie {\n /**\n * Represents a `null` trie element.\n */\n NULL = 0,\n\n /**\n * The default initial size of a trie.\n */\n DEFAULT_SIZE = 655360, // 2.5 MiB\n\n /**\n * The growth factor for resizing a trie.\n */\n GROWTH_FACTOR = 1.6180339887, // ~Phi\n}\n\n/**\n * A pointer can point to either a trie node or a trie redirect.\n *\n * They can be differentiated by the destination's ID value:\n * - If the ID matches the trie's ID, then it's a trie node.\n * - Otherwise, it's a trie redirect.\n */\nexport const enum TriePointerProto {\n // The memory location the pointer points to.\n IDX_IDX = 0,\n IDX_MEM = 1,\n\n // Total memory\n MEM = IDX_MEM,\n}\n\n/**\n * Points to a memory location in a different trie.\n */\nexport const enum TrieRedirectProto {\n // The different trie's ID.\n ID_IDX = 0,\n ID_MEM = 1,\n\n // The memory location of the trie node in the different trie.\n IDX_IDX = 1,\n IDX_MEM = 1,\n\n // Total memory\n MEM = ID_MEM + IDX_MEM,\n}\n\nexport const enum TrieNodeProto {\n // The trie's ID\n ID_IDX = 0,\n ID_MEM = 1,\n\n // The node's value\n VALUE_IDX = 1,\n VALUE_MEM = 1,\n\n // The node's children pointers\n CHILDREN_IDX = 2,\n CHILDREN_LEN = UTF8.BYTE_SPAN,\n CHILDREN_MEM = TriePointerProto.MEM * CHILDREN_LEN,\n\n // Total memory\n MEM = ID_MEM + VALUE_MEM + CHILDREN_MEM,\n}\n\nexport const enum TrieProto {\n // The memory location for the trie's size.\n SIZE_IDX = 0,\n SIZE_MEM = 1,\n\n // The memory location for the trie's root node.\n ROOT_IDX = 1,\n ROOT_MEM = TrieNodeProto.MEM,\n\n // The memory location for the trie's ID (i.e. the root node's trie ID).\n ID_IDX = ROOT_IDX + TrieNodeProto.ID_IDX,\n\n // Total memory\n MEM = SIZE_MEM + ROOT_MEM,\n}\n", "import { WriteStream } from \"node:fs\";\n\nimport { UTF8 } from \"../constants/utf8\";\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n} from \"../constants/utf8Trie\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.add(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { createReadStream } from \"node:fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode } from \"./constants/utf8\";\nimport { Trie, TrieNodeProto } from \"./constants/utf8Trie\";\nimport { parseDouble } from \"./utils/parse\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * BRC.MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(BRC.MAX_ENTRY_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CharCode.NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 4;\n if (buffer[semI - 2] === CharCode.SEMICOLON) {\n semI -= 2;\n } else if (buffer[semI - 1] === CharCode.SEMICOLON) {\n semI -= 1;\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TrieNodeProto.VALUE_IDX] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf + TrieNodeProto.VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TrieNodeProto.VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], + "mappings": "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", + "names": ["TrieNodeProto", "TrieProto", "at", "bt", "res", "run", "run"] } diff --git a/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts b/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts index 5463c44..46c877f 100644 --- a/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts +++ b/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts @@ -1,81 +1,84 @@ -// Configurable constants. -// -// Controls trie behavior such as the default -// allocated size and the growth factor when resizing. - import { UTF8 } from "./utf8"; -/** - * The default initial size of a trie. - */ -export const TRIE_DEFAULT_SIZE = 655360; // 2.5 MiB - -/** - * The growth factor for resizing a trie (Approx. Phi) - */ -export const TRIE_GROWTH_FACTOR = 1.6180339887; - -// Trie pointer -// -// A pointer can point to either a trie node or a trie redirect. -// They can be differentiated by the destination's ID value: -// - If the ID matches the trie's ID, then it's a trie node. -// - Otherwise, it's a trie redirect. - -// The memory location the pointer points to. -export const TRIE_PTR_IDX_IDX = 0; -export const TRIE_PTR_IDX_MEM = 1; - -export const TRIE_PTR_MEM = TRIE_PTR_IDX_MEM; - -// Trie redirect (aka cross-trie pointer) -// -// Points to a memory location in a different trie. - -// The different trie's ID. -export const TRIE_XPTR_ID_IDX = 0; -export const TRIE_XPTR_ID_MEM = 1; +export const enum Trie { + /** + * Represents a `null` trie element. + */ + NULL = 0, -// The memory location of the trie node in the different trie. -export const TRIE_XPTR_IDX_IDX = 1; -export const TRIE_XPTR_IDX_MEM = 1; + /** + * The default initial size of a trie. + */ + DEFAULT_SIZE = 655360, // 2.5 MiB -export const TRIE_XPTR_MEM = TRIE_XPTR_ID_MEM + TRIE_XPTR_IDX_MEM; - -// Trie node - -// The trie's ID -export const TRIE_NODE_ID_IDX = 0; -export const TRIE_NODE_ID_MEM = 1; - -// The node's value -export const TRIE_NODE_VALUE_IDX = 1; -export const TRIE_NODE_VALUE_MEM = 1; - -// The node's children pointers -export const TRIE_NODE_CHILDREN_IDX = 2; -export const TRIE_NODE_CHILDREN_LEN = UTF8.BYTE_SPAN; -export const TRIE_NODE_CHILDREN_MEM = TRIE_PTR_MEM * TRIE_NODE_CHILDREN_LEN; - -export const TRIE_NODE_MEM = - TRIE_NODE_ID_MEM + TRIE_NODE_VALUE_MEM + TRIE_NODE_CHILDREN_MEM; - -// Trie + /** + * The growth factor for resizing a trie. + */ + GROWTH_FACTOR = 1.6180339887, // ~Phi +} /** - * Represents a `null` trie element. + * A pointer can point to either a trie node or a trie redirect. + * + * They can be differentiated by the destination's ID value: + * - If the ID matches the trie's ID, then it's a trie node. + * - Otherwise, it's a trie redirect. */ -export const TRIE_NULL = 0; - -// The memory location for the trie's size. -export const TRIE_SIZE_IDX = 0; -export const TRIE_SIZE_MEM = 1; - -// The memory location for the trie's root node. -export const TRIE_ROOT_IDX = 1; -export const TRIE_ROOT_MEM = TRIE_NODE_MEM; +export const enum TriePointerProto { + // The memory location the pointer points to. + IDX_IDX = 0, + IDX_MEM = 1, -// The memory location for the trie's ID (i.e. the root node's trie ID). -export const TRIE_ID_IDX = TRIE_ROOT_IDX + TRIE_NODE_ID_IDX; + // Total memory + MEM = IDX_MEM, +} -export const TRIE_MEM = TRIE_SIZE_MEM + TRIE_ROOT_MEM; +/** + * Points to a memory location in a different trie. + */ +export const enum TrieRedirectProto { + // The different trie's ID. + ID_IDX = 0, + ID_MEM = 1, + + // The memory location of the trie node in the different trie. + IDX_IDX = 1, + IDX_MEM = 1, + + // Total memory + MEM = ID_MEM + IDX_MEM, +} + +export const enum TrieNodeProto { + // The trie's ID + ID_IDX = 0, + ID_MEM = 1, + + // The node's value + VALUE_IDX = 1, + VALUE_MEM = 1, + + // The node's children pointers + CHILDREN_IDX = 2, + CHILDREN_LEN = UTF8.BYTE_SPAN, + CHILDREN_MEM = TriePointerProto.MEM * CHILDREN_LEN, + + // Total memory + MEM = ID_MEM + VALUE_MEM + CHILDREN_MEM, +} + +export const enum TrieProto { + // The memory location for the trie's size. + SIZE_IDX = 0, + SIZE_MEM = 1, + + // The memory location for the trie's root node. + ROOT_IDX = 1, + ROOT_MEM = TrieNodeProto.MEM, + + // The memory location for the trie's ID (i.e. the root node's trie ID). + ID_IDX = ROOT_IDX + TrieNodeProto.ID_IDX, + + // Total memory + MEM = SIZE_MEM + ROOT_MEM, +} diff --git a/src/main/nodejs/havelessbemore/src/index.ts b/src/main/nodejs/havelessbemore/src/index.ts index baacd07..3d6c0d3 100644 --- a/src/main/nodejs/havelessbemore/src/index.ts +++ b/src/main/nodejs/havelessbemore/src/index.ts @@ -2,11 +2,12 @@ import { availableParallelism } from "node:os"; import { fileURLToPath } from "node:url"; import { isMainThread, parentPort } from "node:worker_threads"; +import type { MergeRequest } from "./types/mergeRequest"; +import type { ProcessRequest } from "./types/processRequest"; +import type { Request } from "./types/request"; + import { run as runMain } from "./main"; import { merge, run as runWorker } from "./worker"; -import { Request } from "./types/request"; -import { ProcessRequest } from "./types/processRequest"; -import { MergeRequest } from "./types/mergeRequest"; if (isMainThread) { const workerPath = fileURLToPath(import.meta.url); diff --git a/src/main/nodejs/havelessbemore/src/main.ts b/src/main/nodejs/havelessbemore/src/main.ts index 7bb10e0..133a1ab 100644 --- a/src/main/nodejs/havelessbemore/src/main.ts +++ b/src/main/nodejs/havelessbemore/src/main.ts @@ -5,11 +5,11 @@ import type { MergeResponse } from "./types/mergeResponse"; import type { ProcessRequest } from "./types/processRequest"; import type { ProcessResponse } from "./types/processResponse"; +import { BRC } from "./constants/brc"; +import { Config } from "./constants/config"; import { clamp, getFileChunks } from "./utils/stream"; import { print } from "./utils/utf8Trie"; import { createWorker, exec } from "./utils/worker"; -import { BRC } from "./constants/brc"; -import { Config } from "./constants/config"; export async function run( filePath: string, diff --git a/src/main/nodejs/havelessbemore/src/utils/stream.ts b/src/main/nodejs/havelessbemore/src/utils/stream.ts index a2ee229..5d1a380 100644 --- a/src/main/nodejs/havelessbemore/src/utils/stream.ts +++ b/src/main/nodejs/havelessbemore/src/utils/stream.ts @@ -1,7 +1,7 @@ import { open } from "fs/promises"; -import { CharCode } from "../constants/utf8"; import { Config } from "../constants/config"; +import { CharCode } from "../constants/utf8"; /** * Clamp a value within a given range. diff --git a/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts b/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts index 06c4dd0..5deed3e 100644 --- a/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts +++ b/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts @@ -1,23 +1,13 @@ import { WriteStream } from "node:fs"; +import { UTF8 } from "../constants/utf8"; import { - TRIE_DEFAULT_SIZE, - TRIE_PTR_MEM, - TRIE_GROWTH_FACTOR, - TRIE_MEM, - TRIE_ID_IDX, - TRIE_NODE_CHILDREN_IDX, - TRIE_NODE_VALUE_IDX, - TRIE_NULL, - TRIE_ROOT_IDX, - TRIE_SIZE_IDX, - TRIE_XPTR_MEM, - TRIE_XPTR_IDX_IDX, - TRIE_NODE_MEM, - TRIE_NODE_CHILDREN_MEM, - TRIE_NODE_CHILDREN_LEN, + Trie, + TrieNodeProto, + TrieProto, + TriePointerProto, + TrieRedirectProto, } from "../constants/utf8Trie"; -import { UTF8 } from "../constants/utf8"; export function add( trie: Int32Array, @@ -25,22 +15,23 @@ export function add( min: number, max: number, ): [Int32Array, number] { - let index = TRIE_ROOT_IDX; + let index: number = TrieProto.ROOT_IDX; while (min < max) { index += - TRIE_NODE_CHILDREN_IDX + /*TRIE_PTR_MEM * */ (key[min++] - UTF8.BYTE_MIN); - let child = trie[index /*+ TRIE_PTR_IDX_IDX*/]; - if (child === TRIE_NULL) { + TrieNodeProto.CHILDREN_IDX + + TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN); + let child = trie[index + TriePointerProto.IDX_IDX]; + if (child === Trie.NULL) { // Allocate node - child = trie[TRIE_SIZE_IDX]; - if (child + TRIE_NODE_MEM > trie.length) { - trie = grow(trie, child + TRIE_NODE_MEM); + child = trie[TrieProto.SIZE_IDX]; + if (child + TrieNodeProto.MEM > trie.length) { + trie = grow(trie, child + TrieNodeProto.MEM); } - trie[TRIE_SIZE_IDX] += TRIE_NODE_MEM; + trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM; // Attach node - trie[index /*+ TRIE_PTR_IDX_IDX*/] = child; + trie[index + TriePointerProto.IDX_IDX] = child; // Initialize node - trie[child /* + TRIE_NODE_ID_IDX*/] = trie[TRIE_ID_IDX]; + trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX]; } index = child; } @@ -55,20 +46,20 @@ export function get( min: number, max: number, ): number | undefined { - let node = TRIE_ROOT_IDX; + let node: number = TrieProto.ROOT_IDX; while (min < max) { const ptr = node + - TRIE_NODE_CHILDREN_IDX + - /*TRIE_PTR_MEM * */ (key[min++] - UTF8.BYTE_MIN); - let child = tries[trie][ptr /* + TRIE_PTR_IDX_IDX*/]; - if (child === TRIE_NULL) { + TrieNodeProto.CHILDREN_IDX + + TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN); + let child = tries[trie][ptr + TriePointerProto.IDX_IDX]; + if (child === Trie.NULL) { return undefined; } // Resolve redirect, if any - const childTrie = tries[trie][child /* + TRIE_NODE_ID_IDX*/]; + const childTrie = tries[trie][child + TrieNodeProto.ID_IDX]; if (childTrie !== trie) { - child = tries[trie][child + TRIE_XPTR_IDX_IDX]; + child = tries[trie][child + TrieRedirectProto.IDX_IDX]; trie = childTrie; } node = child; @@ -76,17 +67,17 @@ export function get( return node; } -export function createTrie(id = 0, size = TRIE_DEFAULT_SIZE): Int32Array { - size = Math.max(TRIE_MEM, size); +export function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array { + size = Math.max(TrieProto.MEM, size); const trie = new Int32Array(new SharedArrayBuffer(size << 2)); - trie[TRIE_SIZE_IDX] = TRIE_MEM; - trie[TRIE_ID_IDX] = id; + trie[TrieProto.SIZE_IDX] = TrieProto.MEM; + trie[TrieProto.ID_IDX] = id; return trie; } export function grow(trie: Int32Array, minSize = 0): Int32Array { - const length = trie[TRIE_SIZE_IDX]; - minSize = Math.max(minSize, Math.ceil(length * TRIE_GROWTH_FACTOR)); + const length = trie[TrieProto.SIZE_IDX]; + minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR)); const next = new Int32Array(new SharedArrayBuffer(minSize << 2)); for (let i = 0; i < length; ++i) { next[i] = trie[i]; @@ -102,7 +93,7 @@ export function mergeLeft( ): number[] { const grown = new Set(); const queue: [number, number, number, number][] = [ - [at, TRIE_ROOT_IDX, bt, TRIE_ROOT_IDX], + [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX], ]; do { @@ -112,53 +103,53 @@ export function mergeLeft( let [at, ai, bt, bi] = queue[q]; // If right value is not null - const bvi = tries[bt][bi + TRIE_NODE_VALUE_IDX]; - if (bvi !== TRIE_NULL) { + const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX]; + if (bvi !== Trie.NULL) { // If left value is not null - const avi = tries[at][ai + TRIE_NODE_VALUE_IDX]; - if (avi !== TRIE_NULL) { + const avi = tries[at][ai + TrieNodeProto.VALUE_IDX]; + if (avi !== Trie.NULL) { mergeFn(avi, bvi); } else { - tries[at][ai + TRIE_NODE_VALUE_IDX] = bvi; + tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi; } } // Adjust to children property - ai += TRIE_NODE_CHILDREN_IDX; - bi += TRIE_NODE_CHILDREN_IDX; + ai += TrieNodeProto.CHILDREN_IDX; + bi += TrieNodeProto.CHILDREN_IDX; // Traverse right children - const bn = bi + TRIE_NODE_CHILDREN_MEM; + const bn = bi + TrieNodeProto.CHILDREN_MEM; while (bi < bn) { // If right child is null - let ri = tries[bt][bi /* + TRIE_PTR_IDX_IDX*/]; - if (ri !== TRIE_NULL) { + let ri = tries[bt][bi + TriePointerProto.IDX_IDX]; + if (ri !== Trie.NULL) { // Resolve right child if redirect - const rt = tries[bt][ri /*+ TRIE_NODE_ID_IDX*/]; + const rt = tries[bt][ri + TrieNodeProto.ID_IDX]; if (bt !== rt) { - ri = tries[bt][ri + TRIE_XPTR_IDX_IDX]; + ri = tries[bt][ri + TrieRedirectProto.IDX_IDX]; } // If left child is null - let li = tries[at][ai /*+ TRIE_PTR_IDX_IDX*/]; - if (li === TRIE_NULL) { + let li = tries[at][ai + TriePointerProto.IDX_IDX]; + if (li === Trie.NULL) { // Allocate redirect - li = tries[at][TRIE_SIZE_IDX]; - if (li + TRIE_XPTR_MEM > tries[at].length) { - tries[at] = grow(tries[at], li + TRIE_XPTR_MEM); + li = tries[at][TrieProto.SIZE_IDX]; + if (li + TrieRedirectProto.MEM > tries[at].length) { + tries[at] = grow(tries[at], li + TrieRedirectProto.MEM); grown.add(at); } - tries[at][TRIE_SIZE_IDX] += TRIE_XPTR_MEM; + tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM; // Attach redirect - tries[at][ai /*+ TRIE_PTR_IDX_IDX*/] = li; + tries[at][ai + TriePointerProto.IDX_IDX] = li; // Initialize redirect - tries[at][li /* + TRIE_XPTR_ID_IDX*/] = rt; - tries[at][li + TRIE_XPTR_IDX_IDX] = ri; + tries[at][li + TrieRedirectProto.ID_IDX] = rt; + tries[at][li + TrieRedirectProto.IDX_IDX] = ri; } else { // Resolve left child if redirect - const lt = tries[at][li /* + TRIE_NODE_ID_IDX*/]; + const lt = tries[at][li + TrieNodeProto.ID_IDX]; if (at !== lt) { - li = tries[at][li + TRIE_XPTR_IDX_IDX]; + li = tries[at][li + TrieRedirectProto.IDX_IDX]; } // Merge children queue.push([lt, li, rt, ri]); @@ -166,8 +157,8 @@ export function mergeLeft( } // Move to next children - ai += TRIE_PTR_MEM; - bi += TRIE_PTR_MEM; + ai += TriePointerProto.MEM; + bi += TriePointerProto.MEM; } } queue.splice(0, Q); @@ -189,7 +180,7 @@ export function print( ) => void, ): void { const stack = new Array<[number, number, number]>(key.length + 1); - stack[0] = [trieIndex, TRIE_ROOT_IDX + TRIE_NODE_CHILDREN_IDX, 0]; + stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0]; let top = 0; let tail = false; @@ -198,35 +189,35 @@ export function print( let [trieI, childPtr, numChild] = stack[top]; // Check if end of children array - if (numChild >= TRIE_NODE_CHILDREN_LEN) { + if (numChild >= TrieNodeProto.CHILDREN_LEN) { --top; continue; } // Update stack top - stack[top][1] += TRIE_PTR_MEM; + stack[top][1] += TriePointerProto.MEM; ++stack[top][2]; // Check if child exists - let childI = tries[trieI][childPtr /* + TRIE_PTR_IDX_IDX*/]; - if (childI === TRIE_NULL) { + let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX]; + if (childI === Trie.NULL) { continue; } // Resolve redirect, if any - const childTrieI = tries[trieI][childI /* + TRIE_NODE_ID_IDX*/]; + const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX]; if (trieI !== childTrieI) { - childI = tries[trieI][childI + TRIE_XPTR_IDX_IDX]; + childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX]; trieI = childTrieI; } // Add the child to the stack key[top] = numChild + UTF8.BYTE_MIN; - stack[++top] = [trieI, childI + TRIE_NODE_CHILDREN_IDX, 0]; + stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0]; // Print value, if any - const valueIndex = tries[trieI][childI + TRIE_NODE_VALUE_IDX]; - if (valueIndex !== TRIE_NULL) { + const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX]; + if (valueIndex !== Trie.NULL) { // Print separator if not first value if (tail) { stream.write(separator); diff --git a/src/main/nodejs/havelessbemore/src/worker.ts b/src/main/nodejs/havelessbemore/src/worker.ts index 41de611..a58146f 100644 --- a/src/main/nodejs/havelessbemore/src/worker.ts +++ b/src/main/nodejs/havelessbemore/src/worker.ts @@ -1,16 +1,16 @@ import { createReadStream } from "node:fs"; +import type { MergeRequest } from "./types/mergeRequest"; +import type { MergeResponse } from "./types/mergeResponse"; import type { ProcessRequest } from "./types/processRequest"; import type { ProcessResponse } from "./types/processResponse"; -import { TRIE_NODE_VALUE_IDX, TRIE_NULL } from "./constants/utf8Trie"; +import { BRC } from "./constants/brc"; +import { CharCode } from "./constants/utf8"; +import { Trie, TrieNodeProto } from "./constants/utf8Trie"; +import { parseDouble } from "./utils/parse"; import { getHighWaterMark } from "./utils/stream"; import { add, createTrie, mergeLeft } from "./utils/utf8Trie"; -import { MergeRequest } from "./types/mergeRequest"; -import { MergeResponse } from "./types/mergeResponse"; -import { parseDouble } from "./utils/parse"; -import { CharCode } from "./constants/utf8"; -import { BRC } from "./constants/brc"; export async function run({ end, @@ -69,12 +69,12 @@ export async function run({ [trie, leaf] = add(trie, buffer, 0, semI); // If the station existed - if (trie[leaf + TRIE_NODE_VALUE_IDX] !== TRIE_NULL) { + if (trie[leaf + TrieNodeProto.VALUE_IDX] !== Trie.NULL) { // Update the station's value - updateStation(trie[leaf + TRIE_NODE_VALUE_IDX], tempV); + updateStation(trie[leaf + TrieNodeProto.VALUE_IDX], tempV); } else { // Add the new station's value - trie[leaf + TRIE_NODE_VALUE_IDX] = stations; + trie[leaf + TrieNodeProto.VALUE_IDX] = stations; newStation(stations++, tempV); } } From 25182511a56bfc5876c52d6d7178ccce747c7b5a Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Sat, 25 May 2024 13:39:24 -0400 Subject: [PATCH 44/69] Update README.md --- src/main/nodejs/havelessbemore/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/nodejs/havelessbemore/README.md b/src/main/nodejs/havelessbemore/README.md index 70543e6..d3b0eb6 100644 --- a/src/main/nodejs/havelessbemore/README.md +++ b/src/main/nodejs/havelessbemore/README.md @@ -53,4 +53,4 @@ npm install npm run build ``` -Output will be in the `dist/` directory. Both CommonJs (`.cjs`) and ECMAScript (`.mjs`) modules are created. +Output is built in the `dist/` directory as ECMAScript (`.mjs`) modules. From 998734b9ea29687ad8aa4142d96afbf6c5f9216b Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Sat, 25 May 2024 13:51:23 -0400 Subject: [PATCH 45/69] Update benchmark results --- src/main/nodejs/havelessbemore/README.md | 6 +- src/main/nodejs/havelessbemore/dist/index.mjs | 408 +----------------- .../nodejs/havelessbemore/dist/index.mjs.map | 4 +- .../nodejs/havelessbemore/esbuild.config.js | 2 +- 4 files changed, 9 insertions(+), 411 deletions(-) diff --git a/src/main/nodejs/havelessbemore/README.md b/src/main/nodejs/havelessbemore/README.md index d3b0eb6..2fbe76b 100644 --- a/src/main/nodejs/havelessbemore/README.md +++ b/src/main/nodejs/havelessbemore/README.md @@ -14,8 +14,10 @@ ### Results -- Min: 13.9s -- Avg: 14.5s +- Min: 13.7s +- Avg: 14.2s +- Max: 14.6s +- Samples: 5 consecutive runs #### Specs: diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index 4e5b995..5c477b3 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -1,407 +1,3 @@ -// src/index.ts -import { availableParallelism } from "node:os"; -import { fileURLToPath } from "node:url"; -import { isMainThread, parentPort } from "node:worker_threads"; - -// src/main.ts -import { createWriteStream } from "node:fs"; - -// src/utils/stream.ts -import { open } from "fs/promises"; -function clamp(value, min, max) { - return value > min ? value <= max ? value : max : min; -} -async function getFileChunks(filePath, target, maxLineLength, minSize = 0) { - const file = await open(filePath); - try { - const size = (await file.stat()).size; - const chunkSize = Math.max(minSize, Math.floor(size / target)); - const buffer = Buffer.allocUnsafe(maxLineLength); - const chunks = []; - let start = 0; - for (let end = chunkSize; end < size; end += chunkSize) { - const res = await file.read(buffer, 0, maxLineLength, end); - const newline = buffer.indexOf(10 /* NEWLINE */); - if (newline >= 0 && newline < res.bytesRead) { - end += newline + 1; - chunks.push([start, end]); - start = end; - } - } - if (start < size) { - chunks.push([start, size]); - } - return chunks; - } finally { - await file.close(); - } -} -function getHighWaterMark(size) { - size *= 152e-6 /* HIGH_WATER_MARK_RATIO */; - size = Math.round(Math.log2(size)); - size = 2 ** size; - return clamp(size, 16384 /* HIGH_WATER_MARK_MIN */, 1048576 /* HIGH_WATER_MARK_MAX */); -} - -// src/constants/utf8Trie.ts -var TrieNodeProto = ((TrieNodeProto2) => { - TrieNodeProto2[TrieNodeProto2["ID_IDX"] = 0] = "ID_IDX"; - TrieNodeProto2[TrieNodeProto2["ID_MEM"] = 1] = "ID_MEM"; - TrieNodeProto2[TrieNodeProto2["VALUE_IDX"] = 1] = "VALUE_IDX"; - TrieNodeProto2[TrieNodeProto2["VALUE_MEM"] = 1] = "VALUE_MEM"; - TrieNodeProto2[TrieNodeProto2["CHILDREN_IDX"] = 2] = "CHILDREN_IDX"; - TrieNodeProto2[TrieNodeProto2["CHILDREN_LEN"] = 216 /* BYTE_SPAN */] = "CHILDREN_LEN"; - TrieNodeProto2[TrieNodeProto2["CHILDREN_MEM"] = 1 /* MEM */ * TrieNodeProto2.CHILDREN_LEN] = "CHILDREN_MEM"; - TrieNodeProto2[TrieNodeProto2["MEM"] = 2 + TrieNodeProto2.CHILDREN_MEM] = "MEM"; - return TrieNodeProto2; -})(TrieNodeProto || {}); -var TrieProto = ((TrieProto2) => { - TrieProto2[TrieProto2["SIZE_IDX"] = 0] = "SIZE_IDX"; - TrieProto2[TrieProto2["SIZE_MEM"] = 1] = "SIZE_MEM"; - TrieProto2[TrieProto2["ROOT_IDX"] = 1] = "ROOT_IDX"; - TrieProto2[TrieProto2["ROOT_MEM"] = TrieNodeProto.MEM] = "ROOT_MEM"; - TrieProto2[TrieProto2["ID_IDX"] = 1] = "ID_IDX"; - TrieProto2[TrieProto2["MEM"] = 1 /* SIZE_MEM */ + TrieProto2.ROOT_MEM] = "MEM"; - return TrieProto2; -})(TrieProto || {}); - -// src/utils/utf8Trie.ts -function add(trie, key, min, max) { - let index = 1 /* ROOT_IDX */; - while (min < max) { - index += 2 /* CHILDREN_IDX */ + 1 /* MEM */ * (key[min++] - 32 /* BYTE_MIN */); - let child = trie[index + 0 /* IDX_IDX */]; - if (child === 0 /* NULL */) { - child = trie[0 /* SIZE_IDX */]; - if (child + TrieNodeProto.MEM > trie.length) { - trie = grow(trie, child + TrieNodeProto.MEM); - } - trie[0 /* SIZE_IDX */] += TrieNodeProto.MEM; - trie[index + 0 /* IDX_IDX */] = child; - trie[child + 0 /* ID_IDX */] = trie[1 /* ID_IDX */]; - } - index = child; - } - return [trie, index]; -} -function createTrie(id = 0, size = 655360 /* DEFAULT_SIZE */) { - size = Math.max(TrieProto.MEM, size); - const trie = new Int32Array(new SharedArrayBuffer(size << 2)); - trie[0 /* SIZE_IDX */] = TrieProto.MEM; - trie[1 /* ID_IDX */] = id; - return trie; -} -function grow(trie, minSize = 0) { - const length = trie[0 /* SIZE_IDX */]; - minSize = Math.max(minSize, Math.ceil(length * 1.6180339887 /* GROWTH_FACTOR */)); - const next = new Int32Array(new SharedArrayBuffer(minSize << 2)); - for (let i = 0; i < length; ++i) { - next[i] = trie[i]; - } - return next; -} -function mergeLeft(tries, at, bt, mergeFn) { - const grown = /* @__PURE__ */ new Set(); - const queue = [ - [at, 1 /* ROOT_IDX */, bt, 1 /* ROOT_IDX */] - ]; - do { - const Q = queue.length; - for (let q = 0; q < Q; ++q) { - let [at2, ai, bt2, bi] = queue[q]; - const bvi = tries[bt2][bi + 1 /* VALUE_IDX */]; - if (bvi !== 0 /* NULL */) { - const avi = tries[at2][ai + 1 /* VALUE_IDX */]; - if (avi !== 0 /* NULL */) { - mergeFn(avi, bvi); - } else { - tries[at2][ai + 1 /* VALUE_IDX */] = bvi; - } - } - ai += 2 /* CHILDREN_IDX */; - bi += 2 /* CHILDREN_IDX */; - const bn = bi + TrieNodeProto.CHILDREN_MEM; - while (bi < bn) { - let ri = tries[bt2][bi + 0 /* IDX_IDX */]; - if (ri !== 0 /* NULL */) { - const rt = tries[bt2][ri + 0 /* ID_IDX */]; - if (bt2 !== rt) { - ri = tries[bt2][ri + 1 /* IDX_IDX */]; - } - let li = tries[at2][ai + 0 /* IDX_IDX */]; - if (li === 0 /* NULL */) { - li = tries[at2][0 /* SIZE_IDX */]; - if (li + 2 /* MEM */ > tries[at2].length) { - tries[at2] = grow(tries[at2], li + 2 /* MEM */); - grown.add(at2); - } - tries[at2][0 /* SIZE_IDX */] += 2 /* MEM */; - tries[at2][ai + 0 /* IDX_IDX */] = li; - tries[at2][li + 0 /* ID_IDX */] = rt; - tries[at2][li + 1 /* IDX_IDX */] = ri; - } else { - const lt = tries[at2][li + 0 /* ID_IDX */]; - if (at2 !== lt) { - li = tries[at2][li + 1 /* IDX_IDX */]; - } - queue.push([lt, li, rt, ri]); - } - } - ai += 1 /* MEM */; - bi += 1 /* MEM */; - } - } - queue.splice(0, Q); - } while (queue.length > 0); - return Array.from(grown); -} -function print(tries, key, trieIndex, stream, separator = "", callbackFn) { - const stack = new Array(key.length + 1); - stack[0] = [trieIndex, 1 /* ROOT_IDX */ + 2 /* CHILDREN_IDX */, 0]; - let top = 0; - let tail = false; - do { - let [trieI, childPtr, numChild] = stack[top]; - if (numChild >= TrieNodeProto.CHILDREN_LEN) { - --top; - continue; - } - stack[top][1] += 1 /* MEM */; - ++stack[top][2]; - let childI = tries[trieI][childPtr + 0 /* IDX_IDX */]; - if (childI === 0 /* NULL */) { - continue; - } - const childTrieI = tries[trieI][childI + 0 /* ID_IDX */]; - if (trieI !== childTrieI) { - childI = tries[trieI][childI + 1 /* IDX_IDX */]; - trieI = childTrieI; - } - key[top] = numChild + 32 /* BYTE_MIN */; - stack[++top] = [trieI, childI + 2 /* CHILDREN_IDX */, 0]; - const valueIndex = tries[trieI][childI + 1 /* VALUE_IDX */]; - if (valueIndex !== 0 /* NULL */) { - if (tail) { - stream.write(separator); - } - tail = true; - callbackFn(stream, key, top, valueIndex); - } - } while (top >= 0); -} - -// src/utils/worker.ts -import { Worker } from "worker_threads"; -function createWorker(workerPath) { - const worker = new Worker(workerPath); - worker.on("error", (err) => { - throw err; - }); - worker.on("messageerror", (err) => { - throw err; - }); - worker.on("exit", (code) => { - if (code > 1 || code < 0) { - throw new Error(`Worker ${worker.threadId} exited with code ${code}`); - } - }); - return worker; -} -function exec(worker, req) { - return new Promise((resolve) => { - worker.once("message", resolve); - worker.postMessage(req); - }); -} - -// src/main.ts -async function run(filePath, workerPath, maxWorkers, outPath = "") { - maxWorkers = clamp(maxWorkers, 1 /* WORKERS_MIN */, 512 /* WORKERS_MAX */); - const chunks = await getFileChunks( - filePath, - maxWorkers, - 107 /* MAX_ENTRY_LEN */, - 16384 /* CHUNK_SIZE_MIN */ - ); - maxWorkers = chunks.length; - const valBuf = new SharedArrayBuffer( - 1e4 /* MAX_STATIONS */ * maxWorkers + 1 << 4 - ); - const mins = new Int16Array(valBuf); - const maxes = new Int16Array(valBuf, 2); - const counts = new Uint32Array(valBuf, 4); - const sums = new Float64Array(valBuf, 8); - const tries = new Array(maxWorkers); - const unmerged = []; - const tasks = new Array(maxWorkers); - for (let i = 0; i < maxWorkers; ++i) { - const worker = createWorker(workerPath); - tasks[i] = exec(worker, { - type: "process", - counts, - end: chunks[i][1], - filePath, - id: i, - maxes, - mins, - start: chunks[i][0], - sums - }).then(async (res) => { - const a = res.id; - tries[res.id] = res.trie; - while (unmerged.length > 0) { - const res2 = await exec(worker, { - type: "merge", - a, - b: unmerged.pop(), - counts, - maxes, - mins, - sums, - tries - }); - for (const id of res2.ids) { - tries[id] = res2.tries[id]; - } - } - unmerged.push(a); - return worker.terminate(); - }); - } - await Promise.all(tasks); - const out = createWriteStream(outPath, { - fd: outPath.length < 1 ? 1 : void 0, - flags: "a", - highWaterMark: 1048576 /* HIGH_WATER_MARK_OUT */ - }); - const buffer = Buffer.allocUnsafe(100 /* MAX_STATION_NAME_LEN */); - out.write("{"); - print(tries, buffer, unmerged[0], out, ", ", printStation); - out.end("}\n"); - function printStation(stream, name, nameLen, vi) { - const avg = Math.round(sums[vi << 1] / counts[vi << 2]); - stream.write(name.toString("utf8", 0, nameLen)); - stream.write("="); - stream.write((mins[vi << 3] / 10).toFixed(1)); - stream.write("/"); - stream.write((avg / 10).toFixed(1)); - stream.write("/"); - stream.write((maxes[vi << 3] / 10).toFixed(1)); - } -} - -// src/worker.ts -import { createReadStream } from "node:fs"; - -// src/utils/parse.ts -var CHAR_ZERO_11 = 11 * 48 /* ZERO */; -var CHAR_ZERO_111 = 111 * 48 /* ZERO */; -function parseDouble(b, min, max) { - if (b[min] === 45 /* MINUS */) { - ++min; - return min + 4 > max ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2] : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3]; - } - return min + 4 > max ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11 : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111; -} - -// src/worker.ts -async function run2({ - end, - filePath, - id, - start, - // Shared memory - counts, - maxes, - mins, - sums -}) { - if (start >= end) { - return { id, trie: createTrie(id, 0) }; - } - let trie = createTrie(id); - let stations = id * 1e4 /* MAX_STATIONS */ + 1; - const buffer = Buffer.allocUnsafe(107 /* MAX_ENTRY_LEN */); - const stream = createReadStream(filePath, { - start, - end: end - 1, - highWaterMark: getHighWaterMark(end - start) - }); - let bufI = 0; - let leaf; - for await (const chunk of stream) { - const N = chunk.length; - for (let i = 0; i < N; ++i) { - if (chunk[i] !== 10 /* NEWLINE */) { - buffer[bufI++] = chunk[i]; - continue; - } - let semI = bufI - 4; - if (buffer[semI - 2] === 59 /* SEMICOLON */) { - semI -= 2; - } else if (buffer[semI - 1] === 59 /* SEMICOLON */) { - semI -= 1; - } - const tempV = parseDouble(buffer, semI + 1, bufI); - bufI = 0; - [trie, leaf] = add(trie, buffer, 0, semI); - if (trie[leaf + 1 /* VALUE_IDX */] !== 0 /* NULL */) { - updateStation(trie[leaf + 1 /* VALUE_IDX */], tempV); - } else { - trie[leaf + 1 /* VALUE_IDX */] = stations; - newStation(stations++, tempV); - } - } - } - function newStation(index, temp) { - mins[index << 3] = temp; - maxes[index << 3] = temp; - counts[index << 2] = 1; - sums[index << 1] = temp; - } - function updateStation(index, temp) { - index <<= 3; - mins[index] = mins[index] <= temp ? mins[index] : temp; - maxes[index] = maxes[index] >= temp ? maxes[index] : temp; - ++counts[index >> 1]; - sums[index >> 2] += temp; - } - return { id, trie }; -} -function merge({ - a, - b, - tries, - counts, - maxes, - mins, - sums -}) { - function mergeStations(ai, bi) { - ai <<= 3; - bi <<= 3; - mins[ai] = Math.min(mins[ai], mins[bi]); - maxes[ai] = Math.max(maxes[ai], maxes[bi]); - counts[ai >> 1] += counts[bi >> 1]; - sums[ai >> 2] += sums[bi >> 2]; - } - const ids = mergeLeft(tries, a, b, mergeStations); - return { ids, tries }; -} - -// src/index.ts -if (isMainThread) { - const workerPath = fileURLToPath(import.meta.url); - run(process.argv[2], workerPath, availableParallelism()); -} else { - parentPort.addListener("message", async (msg) => { - if (msg.type === "process") { - parentPort.postMessage(await run2(msg)); - } else if (msg.type === "merge") { - parentPort.postMessage(merge(msg)); - } else { - throw new Error("Unknown message type"); - } - }); -} +import{availableParallelism as G}from"node:os";import{fileURLToPath as Y}from"node:url";import{isMainThread as Q,parentPort as b}from"node:worker_threads";import{createWriteStream as V}from"node:fs";import{open as F}from"fs/promises";function A(e,t,n){return e>t?e<=n?e:n:t}async function S(e,t,n,p=0){let a=await F(e);try{let u=(await a.stat()).size,s=Math.max(p,Math.floor(u/t)),m=Buffer.allocUnsafe(n),r=[],f=0;for(let I=s;I=0&&c<_.bytesRead&&(I+=c+1,r.push([f,I]),f=I)}return f(r[r.ID_IDX=0]="ID_IDX",r[r.ID_MEM=1]="ID_MEM",r[r.VALUE_IDX=1]="VALUE_IDX",r[r.VALUE_MEM=1]="VALUE_MEM",r[r.CHILDREN_IDX=2]="CHILDREN_IDX",r[r.CHILDREN_LEN=216]="CHILDREN_LEN",r[r.CHILDREN_MEM=1*r.CHILDREN_LEN]="CHILDREN_MEM",r[r.MEM=2+r.CHILDREN_MEM]="MEM",r))(X||{}),g=(s=>(s[s.SIZE_IDX=0]="SIZE_IDX",s[s.SIZE_MEM=1]="SIZE_MEM",s[s.ROOT_IDX=1]="ROOT_IDX",s[s.ROOT_MEM=X.MEM]="ROOT_MEM",s[s.ID_IDX=1]="ID_IDX",s[s.MEM=1+s.ROOT_MEM]="MEM",s))(g||{});function O(e,t,n,p){let a=1;for(;ne.length&&(e=U(e,u+X.MEM)),e[0]+=X.MEM,e[a+0]=u,e[u+0]=e[1]),a=u}return[e,a]}function y(e=0,t=655360){t=Math.max(g.MEM,t);let n=new Int32Array(new SharedArrayBuffer(t<<2));return n[0]=g.MEM,n[1]=e,n}function U(e,t=0){let n=e[0];t=Math.max(t,Math.ceil(n*1.6180339887));let p=new Int32Array(new SharedArrayBuffer(t<<2));for(let a=0;ae[r].length&&(e[r]=U(e[r],o+2),a.add(r)),e[r][0]+=2,e[r][f+0]=o,e[r][o+0]=i,e[r][o+1]=D;else{let M=e[r][o+0];r!==M&&(o=e[r][o+1]),u.push([M,o,i,D])}}f+=1,_+=1}}u.splice(0,s)}while(u.length>0);return Array.from(a)}function d(e,t,n,p,a="",u){let s=new Array(t.length+1);s[0]=[n,3,0];let m=0,r=!1;do{let[f,I,_]=s[m];if(_>=X.CHILDREN_LEN){--m;continue}s[m][1]+=1,++s[m][2];let c=e[f][I+0];if(c===0)continue;let E=e[f][c+0];f!==E&&(c=e[f][c+1],f=E),t[m]=_+32,s[++m]=[f,c+2,0];let D=e[f][c+1];D!==0&&(r&&p.write(a),r=!0,u(p,t,m,D))}while(m>=0)}import{Worker as v}from"worker_threads";function H(e){let t=new v(e);return t.on("error",n=>{throw n}),t.on("messageerror",n=>{throw n}),t.on("exit",n=>{if(n>1||n<0)throw new Error(`Worker ${t.threadId} exited with code ${n}`)}),t}function L(e,t){return new Promise(n=>{e.once("message",n),e.postMessage(t)})}async function q(e,t,n,p=""){n=A(n,1,512);let a=await S(e,n,107,16384);n=a.length;let u=new SharedArrayBuffer(1e4*n+1<<4),s=new Int16Array(u),m=new Int16Array(u,2),r=new Uint32Array(u,4),f=new Float64Array(u,8),I=new Array(n),_=[],c=new Array(n);for(let o=0;o{let l=R.id;for(I[R.id]=R.trie;_.length>0;){let h=await L(M,{type:"merge",a:l,b:_.pop(),counts:r,maxes:m,mins:s,sums:f,tries:I});for(let w of h.ids)I[w]=h.tries[w]}return _.push(l),M.terminate()})}await Promise.all(c);let E=V(p,{fd:p.length<1?1:void 0,flags:"a",highWaterMark:1048576}),D=Buffer.allocUnsafe(100);E.write("{"),d(I,D,_[0],E,", ",i),E.end(`} +`);function i(o,M,R,l){let h=Math.round(f[l<<1]/r[l<<2]);o.write(M.toString("utf8",0,R)),o.write("="),o.write((s[l<<3]/10).toFixed(1)),o.write("/"),o.write((h/10).toFixed(1)),o.write("/"),o.write((m[l<<3]/10).toFixed(1))}}import{createReadStream as K}from"node:fs";var B=11*48,W=111*48;function k(e,t,n){return e[t]===45?(++t,t+4>n?B-10*e[t]-e[t+2]:W-100*e[t]-10*e[t+1]-e[t+3]):t+4>n?10*e[t]+e[t+2]-B:100*e[t]+10*e[t+1]+e[t+3]-W}async function x({end:e,filePath:t,id:n,start:p,counts:a,maxes:u,mins:s,sums:m}){if(p>=e)return{id:n,trie:y(n,0)};let r=y(n),f=n*1e4+1,I=Buffer.allocUnsafe(107),_=K(t,{start:p,end:e-1,highWaterMark:N(e-p)}),c=0,E;for await(let o of _){let M=o.length;for(let R=0;R=M?u[o]:M,++a[o>>1],m[o>>2]+=M}return{id:n,trie:r}}function Z({a:e,b:t,tries:n,counts:p,maxes:a,mins:u,sums:s}){function m(f,I){f<<=3,I<<=3,u[f]=Math.min(u[f],u[I]),a[f]=Math.max(a[f],a[I]),p[f>>1]+=p[I>>1],s[f>>2]+=s[I>>2]}return{ids:C(n,e,t,m),tries:n}}if(Q){let e=Y(import.meta.url);q(process.argv[2],e,G())}else b.addListener("message",async e=>{if(e.type==="process")b.postMessage(await x(e));else if(e.type==="merge")b.postMessage(Z(e));else throw new Error("Unknown message type")}); //# sourceMappingURL=index.mjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index 1a1fc8e..56ec33f 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -2,6 +2,6 @@ "version": 3, "sources": ["../src/index.ts", "../src/main.ts", "../src/utils/stream.ts", "../src/constants/utf8Trie.ts", "../src/utils/utf8Trie.ts", "../src/utils/worker.ts", "../src/worker.ts", "../src/utils/parse.ts"], "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === \"process\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { WriteStream, createWriteStream } from \"node:fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n BRC.MAX_ENTRY_LEN,\n Config.CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: \"process\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[res.id] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: \"merge\",\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { open } from \"fs/promises\";\n\nimport { Config } from \"../constants/config\";\nimport { CharCode } from \"../constants/utf8\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CharCode.NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= Config.HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, Config.HIGH_WATER_MARK_MIN, Config.HIGH_WATER_MARK_MAX);\n}\n", "import { UTF8 } from \"./utf8\";\n\nexport const enum Trie {\n /**\n * Represents a `null` trie element.\n */\n NULL = 0,\n\n /**\n * The default initial size of a trie.\n */\n DEFAULT_SIZE = 655360, // 2.5 MiB\n\n /**\n * The growth factor for resizing a trie.\n */\n GROWTH_FACTOR = 1.6180339887, // ~Phi\n}\n\n/**\n * A pointer can point to either a trie node or a trie redirect.\n *\n * They can be differentiated by the destination's ID value:\n * - If the ID matches the trie's ID, then it's a trie node.\n * - Otherwise, it's a trie redirect.\n */\nexport const enum TriePointerProto {\n // The memory location the pointer points to.\n IDX_IDX = 0,\n IDX_MEM = 1,\n\n // Total memory\n MEM = IDX_MEM,\n}\n\n/**\n * Points to a memory location in a different trie.\n */\nexport const enum TrieRedirectProto {\n // The different trie's ID.\n ID_IDX = 0,\n ID_MEM = 1,\n\n // The memory location of the trie node in the different trie.\n IDX_IDX = 1,\n IDX_MEM = 1,\n\n // Total memory\n MEM = ID_MEM + IDX_MEM,\n}\n\nexport const enum TrieNodeProto {\n // The trie's ID\n ID_IDX = 0,\n ID_MEM = 1,\n\n // The node's value\n VALUE_IDX = 1,\n VALUE_MEM = 1,\n\n // The node's children pointers\n CHILDREN_IDX = 2,\n CHILDREN_LEN = UTF8.BYTE_SPAN,\n CHILDREN_MEM = TriePointerProto.MEM * CHILDREN_LEN,\n\n // Total memory\n MEM = ID_MEM + VALUE_MEM + CHILDREN_MEM,\n}\n\nexport const enum TrieProto {\n // The memory location for the trie's size.\n SIZE_IDX = 0,\n SIZE_MEM = 1,\n\n // The memory location for the trie's root node.\n ROOT_IDX = 1,\n ROOT_MEM = TrieNodeProto.MEM,\n\n // The memory location for the trie's ID (i.e. the root node's trie ID).\n ID_IDX = ROOT_IDX + TrieNodeProto.ID_IDX,\n\n // Total memory\n MEM = SIZE_MEM + ROOT_MEM,\n}\n", "import { WriteStream } from \"node:fs\";\n\nimport { UTF8 } from \"../constants/utf8\";\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n} from \"../constants/utf8Trie\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.add(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { createReadStream } from \"node:fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode } from \"./constants/utf8\";\nimport { Trie, TrieNodeProto } from \"./constants/utf8Trie\";\nimport { parseDouble } from \"./utils/parse\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * BRC.MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(BRC.MAX_ENTRY_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CharCode.NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 4;\n if (buffer[semI - 2] === CharCode.SEMICOLON) {\n semI -= 2;\n } else if (buffer[semI - 1] === CharCode.SEMICOLON) {\n semI -= 1;\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TrieNodeProto.VALUE_IDX] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf + TrieNodeProto.VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TrieNodeProto.VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], - "mappings": "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", - "names": ["TrieNodeProto", "TrieProto", "at", "bt", "res", "run", "run"] + "mappings": "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", + "names": ["availableParallelism", "fileURLToPath", "isMainThread", "parentPort", "createWriteStream", "open", "clamp", "value", "min", "max", "getFileChunks", "filePath", "target", "maxLineLength", "minSize", "file", "open", "size", "chunkSize", "buffer", "chunks", "start", "end", "res", "newline", "getHighWaterMark", "TrieNodeProto", "TrieProto", "add", "trie", "key", "min", "max", "index", "child", "TrieNodeProto", "grow", "createTrie", "id", "size", "TrieProto", "trie", "grow", "minSize", "length", "next", "i", "mergeLeft", "tries", "at", "bt", "mergeFn", "grown", "queue", "Q", "q", "ai", "bi", "bvi", "avi", "bn", "TrieNodeProto", "ri", "rt", "li", "lt", "print", "key", "trieIndex", "stream", "separator", "callbackFn", "stack", "top", "tail", "trieI", "childPtr", "numChild", "childI", "childTrieI", "valueIndex", "Worker", "createWorker", "workerPath", "worker", "err", "code", "exec", "req", "resolve", "run", "filePath", "workerPath", "maxWorkers", "outPath", "clamp", "chunks", "getFileChunks", "valBuf", "mins", "maxes", "counts", "sums", "tries", "unmerged", "tasks", "i", "worker", "createWorker", "exec", "res", "a", "id", "out", "createWriteStream", "buffer", "print", "printStation", "stream", "name", "nameLen", "vi", "avg", "createReadStream", "CHAR_ZERO_11", "CHAR_ZERO_111", "parseDouble", "b", "min", "max", "run", "end", "filePath", "id", "start", "counts", "maxes", "mins", "sums", "createTrie", "trie", "stations", "buffer", "stream", "createReadStream", "getHighWaterMark", "bufI", "leaf", "chunk", "N", "i", "semI", "tempV", "parseDouble", "add", "updateStation", "newStation", "index", "temp", "merge", "a", "b", "tries", "mergeStations", "ai", "bi", "mergeLeft", "isMainThread", "workerPath", "fileURLToPath", "run", "availableParallelism", "parentPort", "msg", "merge"] } diff --git a/src/main/nodejs/havelessbemore/esbuild.config.js b/src/main/nodejs/havelessbemore/esbuild.config.js index 6465df1..741fdc5 100644 --- a/src/main/nodejs/havelessbemore/esbuild.config.js +++ b/src/main/nodejs/havelessbemore/esbuild.config.js @@ -7,7 +7,7 @@ const options = { entryPoints: ["src/index.ts"], bundle: true, drop: ["console"], - minify: false, + minify: true, platform: "node", sourcemap: true, target: "ESNext", From 7060be30f160632b5990f5610725badcbd2754c4 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Sat, 25 May 2024 14:51:35 -0400 Subject: [PATCH 46/69] Add eslint ignore rules --- src/main/nodejs/havelessbemore/src/constants/config.ts | 2 ++ src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/main/nodejs/havelessbemore/src/constants/config.ts b/src/main/nodejs/havelessbemore/src/constants/config.ts index 0fbdd67..0f0b4b1 100644 --- a/src/main/nodejs/havelessbemore/src/constants/config.ts +++ b/src/main/nodejs/havelessbemore/src/constants/config.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-duplicate-enum-values */ + export const enum Config { /** * The minimum value in bytes for `highWaterMark`. diff --git a/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts b/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts index 46c877f..bc10f9d 100644 --- a/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts +++ b/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-duplicate-enum-values */ + import { UTF8 } from "./utf8"; export const enum Trie { From 1caffc3a6f204d8c743dc3d5fa5454c6ae5154e8 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Sat, 25 May 2024 23:47:01 -0400 Subject: [PATCH 47/69] Referencing const enum value A from a separate file prevented some values from const enums B and C to not be inlined, which also caused the creation of enums B and C in the built output file. Combining the const enums into one file fixes this so all const enum values are properly inlined. Since these values were in the hot loop, this notably improved performance --- src/main/nodejs/havelessbemore/dist/index.mjs | 4 +- .../nodejs/havelessbemore/dist/index.mjs.map | 8 +- .../havelessbemore/src/constants/utf8.ts | 85 ++++++++++++++++++ .../havelessbemore/src/constants/utf8Trie.ts | 86 ------------------- .../havelessbemore/src/utils/utf8Trie.ts | 4 +- src/main/nodejs/havelessbemore/src/worker.ts | 3 +- 6 files changed, 94 insertions(+), 96 deletions(-) delete mode 100644 src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index 5c477b3..7e3aefe 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -1,3 +1,3 @@ -import{availableParallelism as G}from"node:os";import{fileURLToPath as Y}from"node:url";import{isMainThread as Q,parentPort as b}from"node:worker_threads";import{createWriteStream as V}from"node:fs";import{open as F}from"fs/promises";function A(e,t,n){return e>t?e<=n?e:n:t}async function S(e,t,n,p=0){let a=await F(e);try{let u=(await a.stat()).size,s=Math.max(p,Math.floor(u/t)),m=Buffer.allocUnsafe(n),r=[],f=0;for(let I=s;I=0&&c<_.bytesRead&&(I+=c+1,r.push([f,I]),f=I)}return f(r[r.ID_IDX=0]="ID_IDX",r[r.ID_MEM=1]="ID_MEM",r[r.VALUE_IDX=1]="VALUE_IDX",r[r.VALUE_MEM=1]="VALUE_MEM",r[r.CHILDREN_IDX=2]="CHILDREN_IDX",r[r.CHILDREN_LEN=216]="CHILDREN_LEN",r[r.CHILDREN_MEM=1*r.CHILDREN_LEN]="CHILDREN_MEM",r[r.MEM=2+r.CHILDREN_MEM]="MEM",r))(X||{}),g=(s=>(s[s.SIZE_IDX=0]="SIZE_IDX",s[s.SIZE_MEM=1]="SIZE_MEM",s[s.ROOT_IDX=1]="ROOT_IDX",s[s.ROOT_MEM=X.MEM]="ROOT_MEM",s[s.ID_IDX=1]="ID_IDX",s[s.MEM=1+s.ROOT_MEM]="MEM",s))(g||{});function O(e,t,n,p){let a=1;for(;ne.length&&(e=U(e,u+X.MEM)),e[0]+=X.MEM,e[a+0]=u,e[u+0]=e[1]),a=u}return[e,a]}function y(e=0,t=655360){t=Math.max(g.MEM,t);let n=new Int32Array(new SharedArrayBuffer(t<<2));return n[0]=g.MEM,n[1]=e,n}function U(e,t=0){let n=e[0];t=Math.max(t,Math.ceil(n*1.6180339887));let p=new Int32Array(new SharedArrayBuffer(t<<2));for(let a=0;ae[r].length&&(e[r]=U(e[r],o+2),a.add(r)),e[r][0]+=2,e[r][f+0]=o,e[r][o+0]=i,e[r][o+1]=D;else{let M=e[r][o+0];r!==M&&(o=e[r][o+1]),u.push([M,o,i,D])}}f+=1,_+=1}}u.splice(0,s)}while(u.length>0);return Array.from(a)}function d(e,t,n,p,a="",u){let s=new Array(t.length+1);s[0]=[n,3,0];let m=0,r=!1;do{let[f,I,_]=s[m];if(_>=X.CHILDREN_LEN){--m;continue}s[m][1]+=1,++s[m][2];let c=e[f][I+0];if(c===0)continue;let E=e[f][c+0];f!==E&&(c=e[f][c+1],f=E),t[m]=_+32,s[++m]=[f,c+2,0];let D=e[f][c+1];D!==0&&(r&&p.write(a),r=!0,u(p,t,m,D))}while(m>=0)}import{Worker as v}from"worker_threads";function H(e){let t=new v(e);return t.on("error",n=>{throw n}),t.on("messageerror",n=>{throw n}),t.on("exit",n=>{if(n>1||n<0)throw new Error(`Worker ${t.threadId} exited with code ${n}`)}),t}function L(e,t){return new Promise(n=>{e.once("message",n),e.postMessage(t)})}async function q(e,t,n,p=""){n=A(n,1,512);let a=await S(e,n,107,16384);n=a.length;let u=new SharedArrayBuffer(1e4*n+1<<4),s=new Int16Array(u),m=new Int16Array(u,2),r=new Uint32Array(u,4),f=new Float64Array(u,8),I=new Array(n),_=[],c=new Array(n);for(let o=0;o{let l=R.id;for(I[R.id]=R.trie;_.length>0;){let h=await L(M,{type:"merge",a:l,b:_.pop(),counts:r,maxes:m,mins:s,sums:f,tries:I});for(let w of h.ids)I[w]=h.tries[w]}return _.push(l),M.terminate()})}await Promise.all(c);let E=V(p,{fd:p.length<1?1:void 0,flags:"a",highWaterMark:1048576}),D=Buffer.allocUnsafe(100);E.write("{"),d(I,D,_[0],E,", ",i),E.end(`} -`);function i(o,M,R,l){let h=Math.round(f[l<<1]/r[l<<2]);o.write(M.toString("utf8",0,R)),o.write("="),o.write((s[l<<3]/10).toFixed(1)),o.write("/"),o.write((h/10).toFixed(1)),o.write("/"),o.write((m[l<<3]/10).toFixed(1))}}import{createReadStream as K}from"node:fs";var B=11*48,W=111*48;function k(e,t,n){return e[t]===45?(++t,t+4>n?B-10*e[t]-e[t+2]:W-100*e[t]-10*e[t+1]-e[t+3]):t+4>n?10*e[t]+e[t+2]-B:100*e[t]+10*e[t+1]+e[t+3]-W}async function x({end:e,filePath:t,id:n,start:p,counts:a,maxes:u,mins:s,sums:m}){if(p>=e)return{id:n,trie:y(n,0)};let r=y(n),f=n*1e4+1,I=Buffer.allocUnsafe(107),_=K(t,{start:p,end:e-1,highWaterMark:N(e-p)}),c=0,E;for await(let o of _){let M=o.length;for(let R=0;R=M?u[o]:M,++a[o>>1],m[o>>2]+=M}return{id:n,trie:r}}function Z({a:e,b:t,tries:n,counts:p,maxes:a,mins:u,sums:s}){function m(f,I){f<<=3,I<<=3,u[f]=Math.min(u[f],u[I]),a[f]=Math.max(a[f],a[I]),p[f>>1]+=p[I>>1],s[f>>2]+=s[I>>2]}return{ids:C(n,e,t,m),tries:n}}if(Q){let e=Y(import.meta.url);q(process.argv[2],e,G())}else b.addListener("message",async e=>{if(e.type==="process")b.postMessage(await x(e));else if(e.type==="merge")b.postMessage(Z(e));else throw new Error("Unknown message type")}); +import{availableParallelism as v}from"node:os";import{fileURLToPath as F}from"node:url";import{isMainThread as V,parentPort as b}from"node:worker_threads";import{createWriteStream as x}from"node:fs";import{open as B}from"fs/promises";function h(e,t,r){return e>t?e<=r?e:r:t}async function d(e,t,r,p=0){let i=await B(e);try{let n=(await i.stat()).size,c=Math.max(p,Math.floor(n/t)),a=Buffer.allocUnsafe(r),s=[],u=0;for(let f=c;f=0&&Ie.length&&(e=N(e,n+218)),e[0]+=218,e[i+0]=n,e[n+0]=e[1]),i=n}return[e,i]}function g(e=0,t=655360){t=Math.max(219,t);let r=new Int32Array(new SharedArrayBuffer(t<<2));return r[0]=219,r[1]=e,r}function N(e,t=0){let r=e[0];t=Math.max(t,Math.ceil(r*1.6180339887));let p=new Int32Array(new SharedArrayBuffer(t<<2));for(let i=0;ie[s].length&&(e[s]=N(e[s],o+2),i.add(s)),e[s][0]+=2,e[s][u+0]=o,e[s][o+0]=E,e[s][o+1]=M;else{let m=e[s][o+0];s!==m&&(o=e[s][o+1]),n.push([m,o,E,M])}}u+=1,l+=1}}n.splice(0,c)}while(n.length>0);return Array.from(i)}function S(e,t,r,p,i="",n){let c=new Array(t.length+1);c[0]=[r,3,0];let a=0,s=!1;do{let[u,f,l]=c[a];if(l>=216){--a;continue}c[a][1]+=1,++c[a][2];let I=e[u][f+0];if(I===0)continue;let _=e[u][I+0];u!==_&&(I=e[u][I+1],u=_),t[a]=l+32,c[++a]=[u,I+2,0];let M=e[u][I+1];M!==0&&(s&&p.write(i),s=!0,n(p,t,a,M))}while(a>=0)}import{Worker as W}from"worker_threads";function U(e){let t=new W(e);return t.on("error",r=>{throw r}),t.on("messageerror",r=>{throw r}),t.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${t.threadId} exited with code ${r}`)}),t}function y(e,t){return new Promise(r=>{e.once("message",r),e.postMessage(t)})}async function O(e,t,r,p=""){r=h(r,1,512);let i=await d(e,r,107,16384);r=i.length;let n=new SharedArrayBuffer(1e4*r+1<<4),c=new Int16Array(n),a=new Int16Array(n,2),s=new Uint32Array(n,4),u=new Float64Array(n,8),f=new Array(r),l=[],I=new Array(r);for(let o=0;o{let R=D.id;for(f[D.id]=D.trie;l.length>0;){let X=await y(m,{type:"merge",a:R,b:l.pop(),counts:s,maxes:a,mins:c,sums:u,tries:f});for(let A of X.ids)f[A]=X.tries[A]}return l.push(R),m.terminate()})}await Promise.all(I);let _=x(p,{fd:p.length<1?1:void 0,flags:"a",highWaterMark:1048576}),M=Buffer.allocUnsafe(100);_.write("{"),S(f,M,l[0],_,", ",E),_.end(`} +`);function E(o,m,D,R){let X=Math.round(u[R<<1]/s[R<<2]);o.write(m.toString("utf8",0,D)),o.write("="),o.write((c[R<<3]/10).toFixed(1)),o.write("/"),o.write((X/10).toFixed(1)),o.write("/"),o.write((a[R<<3]/10).toFixed(1))}}import{createReadStream as Z}from"node:fs";var C=11*48,P=111*48;function q(e,t,r){return e[t]===45?(++t,t+4>r?C-10*e[t]-e[t+2]:P-100*e[t]-10*e[t+1]-e[t+3]):t+4>r?10*e[t]+e[t+2]-C:100*e[t]+10*e[t+1]+e[t+3]-P}async function H({end:e,filePath:t,id:r,start:p,counts:i,maxes:n,mins:c,sums:a}){if(p>=e)return{id:r,trie:g(r,0)};let s=g(r),u=r*1e4+1,f=Buffer.allocUnsafe(107),l=Z(t,{start:p,end:e-1,highWaterMark:w(e-p)}),I=0,_;for await(let o of l){let m=o.length;for(let D=0;D=m?n[o]:m,++i[o>>1],a[o>>2]+=m}return{id:r,trie:s}}function k({a:e,b:t,tries:r,counts:p,maxes:i,mins:n,sums:c}){function a(u,f){u<<=3,f<<=3,n[u]=Math.min(n[u],n[f]),i[u]=Math.max(i[u],i[f]),p[u>>1]+=p[f>>1],c[u>>2]+=c[f>>2]}return{ids:T(r,e,t,a),tries:r}}if(V){let e=F(import.meta.url);O(process.argv[2],e,v())}else b.addListener("message",async e=>{if(e.type==="process")b.postMessage(await H(e));else if(e.type==="merge")b.postMessage(k(e));else throw new Error("Unknown message type")}); //# sourceMappingURL=index.mjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index 56ec33f..a9dc877 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1,7 +1,7 @@ { "version": 3, - "sources": ["../src/index.ts", "../src/main.ts", "../src/utils/stream.ts", "../src/constants/utf8Trie.ts", "../src/utils/utf8Trie.ts", "../src/utils/worker.ts", "../src/worker.ts", "../src/utils/parse.ts"], - "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === \"process\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { WriteStream, createWriteStream } from \"node:fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n BRC.MAX_ENTRY_LEN,\n Config.CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: \"process\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[res.id] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: \"merge\",\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { open } from \"fs/promises\";\n\nimport { Config } from \"../constants/config\";\nimport { CharCode } from \"../constants/utf8\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CharCode.NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= Config.HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, Config.HIGH_WATER_MARK_MIN, Config.HIGH_WATER_MARK_MAX);\n}\n", "import { UTF8 } from \"./utf8\";\n\nexport const enum Trie {\n /**\n * Represents a `null` trie element.\n */\n NULL = 0,\n\n /**\n * The default initial size of a trie.\n */\n DEFAULT_SIZE = 655360, // 2.5 MiB\n\n /**\n * The growth factor for resizing a trie.\n */\n GROWTH_FACTOR = 1.6180339887, // ~Phi\n}\n\n/**\n * A pointer can point to either a trie node or a trie redirect.\n *\n * They can be differentiated by the destination's ID value:\n * - If the ID matches the trie's ID, then it's a trie node.\n * - Otherwise, it's a trie redirect.\n */\nexport const enum TriePointerProto {\n // The memory location the pointer points to.\n IDX_IDX = 0,\n IDX_MEM = 1,\n\n // Total memory\n MEM = IDX_MEM,\n}\n\n/**\n * Points to a memory location in a different trie.\n */\nexport const enum TrieRedirectProto {\n // The different trie's ID.\n ID_IDX = 0,\n ID_MEM = 1,\n\n // The memory location of the trie node in the different trie.\n IDX_IDX = 1,\n IDX_MEM = 1,\n\n // Total memory\n MEM = ID_MEM + IDX_MEM,\n}\n\nexport const enum TrieNodeProto {\n // The trie's ID\n ID_IDX = 0,\n ID_MEM = 1,\n\n // The node's value\n VALUE_IDX = 1,\n VALUE_MEM = 1,\n\n // The node's children pointers\n CHILDREN_IDX = 2,\n CHILDREN_LEN = UTF8.BYTE_SPAN,\n CHILDREN_MEM = TriePointerProto.MEM * CHILDREN_LEN,\n\n // Total memory\n MEM = ID_MEM + VALUE_MEM + CHILDREN_MEM,\n}\n\nexport const enum TrieProto {\n // The memory location for the trie's size.\n SIZE_IDX = 0,\n SIZE_MEM = 1,\n\n // The memory location for the trie's root node.\n ROOT_IDX = 1,\n ROOT_MEM = TrieNodeProto.MEM,\n\n // The memory location for the trie's ID (i.e. the root node's trie ID).\n ID_IDX = ROOT_IDX + TrieNodeProto.ID_IDX,\n\n // Total memory\n MEM = SIZE_MEM + ROOT_MEM,\n}\n", "import { WriteStream } from \"node:fs\";\n\nimport { UTF8 } from \"../constants/utf8\";\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n} from \"../constants/utf8Trie\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.add(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { createReadStream } from \"node:fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode } from \"./constants/utf8\";\nimport { Trie, TrieNodeProto } from \"./constants/utf8Trie\";\nimport { parseDouble } from \"./utils/parse\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * BRC.MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(BRC.MAX_ENTRY_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CharCode.NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 4;\n if (buffer[semI - 2] === CharCode.SEMICOLON) {\n semI -= 2;\n } else if (buffer[semI - 1] === CharCode.SEMICOLON) {\n semI -= 1;\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TrieNodeProto.VALUE_IDX] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf + TrieNodeProto.VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TrieNodeProto.VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], - "mappings": "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", - "names": ["availableParallelism", "fileURLToPath", "isMainThread", "parentPort", "createWriteStream", "open", "clamp", "value", "min", "max", "getFileChunks", "filePath", "target", "maxLineLength", "minSize", "file", "open", "size", "chunkSize", "buffer", "chunks", "start", "end", "res", "newline", "getHighWaterMark", "TrieNodeProto", "TrieProto", "add", "trie", "key", "min", "max", "index", "child", "TrieNodeProto", "grow", "createTrie", "id", "size", "TrieProto", "trie", "grow", "minSize", "length", "next", "i", "mergeLeft", "tries", "at", "bt", "mergeFn", "grown", "queue", "Q", "q", "ai", "bi", "bvi", "avi", "bn", "TrieNodeProto", "ri", "rt", "li", "lt", "print", "key", "trieIndex", "stream", "separator", "callbackFn", "stack", "top", "tail", "trieI", "childPtr", "numChild", "childI", "childTrieI", "valueIndex", "Worker", "createWorker", "workerPath", "worker", "err", "code", "exec", "req", "resolve", "run", "filePath", "workerPath", "maxWorkers", "outPath", "clamp", "chunks", "getFileChunks", "valBuf", "mins", "maxes", "counts", "sums", "tries", "unmerged", "tasks", "i", "worker", "createWorker", "exec", "res", "a", "id", "out", "createWriteStream", "buffer", "print", "printStation", "stream", "name", "nameLen", "vi", "avg", "createReadStream", "CHAR_ZERO_11", "CHAR_ZERO_111", "parseDouble", "b", "min", "max", "run", "end", "filePath", "id", "start", "counts", "maxes", "mins", "sums", "createTrie", "trie", "stations", "buffer", "stream", "createReadStream", "getHighWaterMark", "bufI", "leaf", "chunk", "N", "i", "semI", "tempV", "parseDouble", "add", "updateStation", "newStation", "index", "temp", "merge", "a", "b", "tries", "mergeStations", "ai", "bi", "mergeLeft", "isMainThread", "workerPath", "fileURLToPath", "run", "availableParallelism", "parentPort", "msg", "merge"] + "sources": ["../src/index.ts", "../src/main.ts", "../src/utils/stream.ts", "../src/utils/utf8Trie.ts", "../src/utils/worker.ts", "../src/worker.ts", "../src/utils/parse.ts"], + "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === \"process\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { WriteStream, createWriteStream } from \"node:fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n BRC.MAX_ENTRY_LEN,\n Config.CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: \"process\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[res.id] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: \"merge\",\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { open } from \"fs/promises\";\n\nimport { Config } from \"../constants/config\";\nimport { CharCode } from \"../constants/utf8\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CharCode.NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= Config.HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, Config.HIGH_WATER_MARK_MIN, Config.HIGH_WATER_MARK_MAX);\n}\n", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.add(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { createReadStream } from \"node:fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * BRC.MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(BRC.MAX_ENTRY_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CharCode.NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 4;\n if (buffer[semI - 2] === CharCode.SEMICOLON) {\n semI -= 2;\n } else if (buffer[semI - 1] === CharCode.SEMICOLON) {\n semI -= 1;\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TrieNodeProto.VALUE_IDX] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf + TrieNodeProto.VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TrieNodeProto.VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], + "mappings": "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", + "names": ["availableParallelism", "fileURLToPath", "isMainThread", "parentPort", "createWriteStream", "open", "clamp", "value", "min", "max", "getFileChunks", "filePath", "target", "maxLineLength", "minSize", "file", "open", "size", "chunkSize", "buffer", "chunks", "start", "end", "res", "newline", "getHighWaterMark", "add", "trie", "key", "min", "max", "index", "child", "grow", "createTrie", "id", "size", "trie", "grow", "minSize", "length", "next", "mergeLeft", "tries", "at", "bt", "mergeFn", "grown", "queue", "Q", "q", "ai", "bi", "bvi", "avi", "bn", "ri", "rt", "li", "lt", "print", "key", "trieIndex", "stream", "separator", "callbackFn", "stack", "top", "tail", "trieI", "childPtr", "numChild", "childI", "childTrieI", "valueIndex", "Worker", "createWorker", "workerPath", "worker", "err", "code", "exec", "req", "resolve", "run", "filePath", "workerPath", "maxWorkers", "outPath", "clamp", "chunks", "getFileChunks", "valBuf", "mins", "maxes", "counts", "sums", "tries", "unmerged", "tasks", "i", "worker", "createWorker", "exec", "res", "a", "id", "out", "createWriteStream", "buffer", "print", "printStation", "stream", "name", "nameLen", "vi", "avg", "createReadStream", "CHAR_ZERO_11", "CHAR_ZERO_111", "parseDouble", "b", "min", "max", "run", "end", "filePath", "id", "start", "counts", "maxes", "mins", "sums", "createTrie", "trie", "stations", "buffer", "stream", "createReadStream", "getHighWaterMark", "bufI", "leaf", "chunk", "N", "i", "semI", "tempV", "parseDouble", "add", "updateStation", "newStation", "index", "temp", "merge", "a", "b", "tries", "mergeStations", "ai", "bi", "mergeLeft", "isMainThread", "workerPath", "fileURLToPath", "run", "availableParallelism", "parentPort", "msg", "merge"] } diff --git a/src/main/nodejs/havelessbemore/src/constants/utf8.ts b/src/main/nodejs/havelessbemore/src/constants/utf8.ts index 82ee508..65c2cb2 100644 --- a/src/main/nodejs/havelessbemore/src/constants/utf8.ts +++ b/src/main/nodejs/havelessbemore/src/constants/utf8.ts @@ -1,3 +1,5 @@ +/* eslint-disable @typescript-eslint/no-duplicate-enum-values */ + export const enum CharCode { /** * The char code for a minus sign: - @@ -69,3 +71,86 @@ export const enum UTF8 { B0_4B_MAX = 0b11110111, */ } + +export const enum Trie { + /** + * Represents a `null` trie element. + */ + NULL = 0, + + /** + * The default initial size of a trie. + */ + DEFAULT_SIZE = 655360, // 2.5 MiB + + /** + * The growth factor for resizing a trie. + */ + GROWTH_FACTOR = 1.6180339887, +} + +/** + * A pointer can point to either a trie node or a trie redirect. + * + * They can be differentiated by the destination's ID value: + * - If the ID matches the trie's ID, then it's a trie node. + * - Otherwise, it's a trie redirect. + */ +export const enum TriePointerProto { + // The memory location the pointer points to. + IDX_IDX = 0, + IDX_MEM = 1, + + // Total memory + MEM = IDX_MEM, +} + +/** + * Points to a memory location in a different trie. + */ +export const enum TrieRedirectProto { + // The different trie's ID. + ID_IDX = 0, + ID_MEM = 1, + + // The memory location of the trie node in the different trie. + IDX_IDX = 1, + IDX_MEM = 1, + + // Total memory + MEM = ID_MEM + IDX_MEM, +} + +export const enum TrieNodeProto { + // The trie's ID + ID_IDX = 0, + ID_MEM = 1, + + // The node's value + VALUE_IDX = 1, + VALUE_MEM = 1, + + // The node's children pointers + CHILDREN_IDX = 2, + CHILDREN_LEN = UTF8.BYTE_SPAN, + CHILDREN_MEM = TriePointerProto.MEM * CHILDREN_LEN, + + // Total memory + MEM = ID_MEM + VALUE_MEM + CHILDREN_MEM, +} + +export const enum TrieProto { + // The memory location for the trie's size. + SIZE_IDX = 0, + SIZE_MEM = 1, + + // The memory location for the trie's root node. + ROOT_IDX = 1, + ROOT_MEM = TrieNodeProto.MEM, + + // The memory location for the trie's ID (i.e. the root node's trie ID). + ID_IDX = ROOT_IDX + TrieNodeProto.ID_IDX, + + // Total memory + MEM = SIZE_MEM + ROOT_MEM, +} diff --git a/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts b/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts deleted file mode 100644 index bc10f9d..0000000 --- a/src/main/nodejs/havelessbemore/src/constants/utf8Trie.ts +++ /dev/null @@ -1,86 +0,0 @@ -/* eslint-disable @typescript-eslint/no-duplicate-enum-values */ - -import { UTF8 } from "./utf8"; - -export const enum Trie { - /** - * Represents a `null` trie element. - */ - NULL = 0, - - /** - * The default initial size of a trie. - */ - DEFAULT_SIZE = 655360, // 2.5 MiB - - /** - * The growth factor for resizing a trie. - */ - GROWTH_FACTOR = 1.6180339887, // ~Phi -} - -/** - * A pointer can point to either a trie node or a trie redirect. - * - * They can be differentiated by the destination's ID value: - * - If the ID matches the trie's ID, then it's a trie node. - * - Otherwise, it's a trie redirect. - */ -export const enum TriePointerProto { - // The memory location the pointer points to. - IDX_IDX = 0, - IDX_MEM = 1, - - // Total memory - MEM = IDX_MEM, -} - -/** - * Points to a memory location in a different trie. - */ -export const enum TrieRedirectProto { - // The different trie's ID. - ID_IDX = 0, - ID_MEM = 1, - - // The memory location of the trie node in the different trie. - IDX_IDX = 1, - IDX_MEM = 1, - - // Total memory - MEM = ID_MEM + IDX_MEM, -} - -export const enum TrieNodeProto { - // The trie's ID - ID_IDX = 0, - ID_MEM = 1, - - // The node's value - VALUE_IDX = 1, - VALUE_MEM = 1, - - // The node's children pointers - CHILDREN_IDX = 2, - CHILDREN_LEN = UTF8.BYTE_SPAN, - CHILDREN_MEM = TriePointerProto.MEM * CHILDREN_LEN, - - // Total memory - MEM = ID_MEM + VALUE_MEM + CHILDREN_MEM, -} - -export const enum TrieProto { - // The memory location for the trie's size. - SIZE_IDX = 0, - SIZE_MEM = 1, - - // The memory location for the trie's root node. - ROOT_IDX = 1, - ROOT_MEM = TrieNodeProto.MEM, - - // The memory location for the trie's ID (i.e. the root node's trie ID). - ID_IDX = ROOT_IDX + TrieNodeProto.ID_IDX, - - // Total memory - MEM = SIZE_MEM + ROOT_MEM, -} diff --git a/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts b/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts index 5deed3e..fdea362 100644 --- a/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts +++ b/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts @@ -1,13 +1,13 @@ import { WriteStream } from "node:fs"; -import { UTF8 } from "../constants/utf8"; import { Trie, TrieNodeProto, TrieProto, TriePointerProto, TrieRedirectProto, -} from "../constants/utf8Trie"; + UTF8, +} from "../constants/utf8"; export function add( trie: Int32Array, diff --git a/src/main/nodejs/havelessbemore/src/worker.ts b/src/main/nodejs/havelessbemore/src/worker.ts index a58146f..fc2d680 100644 --- a/src/main/nodejs/havelessbemore/src/worker.ts +++ b/src/main/nodejs/havelessbemore/src/worker.ts @@ -6,8 +6,7 @@ import type { ProcessRequest } from "./types/processRequest"; import type { ProcessResponse } from "./types/processResponse"; import { BRC } from "./constants/brc"; -import { CharCode } from "./constants/utf8"; -import { Trie, TrieNodeProto } from "./constants/utf8Trie"; +import { CharCode, Trie, TrieNodeProto } from "./constants/utf8"; import { parseDouble } from "./utils/parse"; import { getHighWaterMark } from "./utils/stream"; import { add, createTrie, mergeLeft } from "./utils/utf8Trie"; From 05dbbd8f7252a40556cecf60c6851fe73a77f156 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Sun, 26 May 2024 00:19:05 -0400 Subject: [PATCH 48/69] Simplify finding an entry's semicolon --- src/main/nodejs/havelessbemore/README.md | 6 +++--- src/main/nodejs/havelessbemore/dist/index.mjs | 4 ++-- src/main/nodejs/havelessbemore/dist/index.mjs.map | 4 ++-- src/main/nodejs/havelessbemore/src/worker.ts | 8 +++----- 4 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/main/nodejs/havelessbemore/README.md b/src/main/nodejs/havelessbemore/README.md index 2fbe76b..ca5ec8c 100644 --- a/src/main/nodejs/havelessbemore/README.md +++ b/src/main/nodejs/havelessbemore/README.md @@ -14,9 +14,9 @@ ### Results -- Min: 13.7s -- Avg: 14.2s -- Max: 14.6s +- Min: 13.2s +- Avg: 13.8s +- Max: 14.2s - Samples: 5 consecutive runs #### Specs: diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index 7e3aefe..f8aa95d 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -1,3 +1,3 @@ -import{availableParallelism as v}from"node:os";import{fileURLToPath as F}from"node:url";import{isMainThread as V,parentPort as b}from"node:worker_threads";import{createWriteStream as x}from"node:fs";import{open as B}from"fs/promises";function h(e,t,r){return e>t?e<=r?e:r:t}async function d(e,t,r,p=0){let i=await B(e);try{let n=(await i.stat()).size,c=Math.max(p,Math.floor(n/t)),a=Buffer.allocUnsafe(r),s=[],u=0;for(let f=c;f=0&&Ie.length&&(e=N(e,n+218)),e[0]+=218,e[i+0]=n,e[n+0]=e[1]),i=n}return[e,i]}function g(e=0,t=655360){t=Math.max(219,t);let r=new Int32Array(new SharedArrayBuffer(t<<2));return r[0]=219,r[1]=e,r}function N(e,t=0){let r=e[0];t=Math.max(t,Math.ceil(r*1.6180339887));let p=new Int32Array(new SharedArrayBuffer(t<<2));for(let i=0;ie[s].length&&(e[s]=N(e[s],o+2),i.add(s)),e[s][0]+=2,e[s][u+0]=o,e[s][o+0]=E,e[s][o+1]=M;else{let m=e[s][o+0];s!==m&&(o=e[s][o+1]),n.push([m,o,E,M])}}u+=1,l+=1}}n.splice(0,c)}while(n.length>0);return Array.from(i)}function S(e,t,r,p,i="",n){let c=new Array(t.length+1);c[0]=[r,3,0];let a=0,s=!1;do{let[u,f,l]=c[a];if(l>=216){--a;continue}c[a][1]+=1,++c[a][2];let I=e[u][f+0];if(I===0)continue;let _=e[u][I+0];u!==_&&(I=e[u][I+1],u=_),t[a]=l+32,c[++a]=[u,I+2,0];let M=e[u][I+1];M!==0&&(s&&p.write(i),s=!0,n(p,t,a,M))}while(a>=0)}import{Worker as W}from"worker_threads";function U(e){let t=new W(e);return t.on("error",r=>{throw r}),t.on("messageerror",r=>{throw r}),t.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${t.threadId} exited with code ${r}`)}),t}function y(e,t){return new Promise(r=>{e.once("message",r),e.postMessage(t)})}async function O(e,t,r,p=""){r=h(r,1,512);let i=await d(e,r,107,16384);r=i.length;let n=new SharedArrayBuffer(1e4*r+1<<4),c=new Int16Array(n),a=new Int16Array(n,2),s=new Uint32Array(n,4),u=new Float64Array(n,8),f=new Array(r),l=[],I=new Array(r);for(let o=0;o{let R=D.id;for(f[D.id]=D.trie;l.length>0;){let X=await y(m,{type:"merge",a:R,b:l.pop(),counts:s,maxes:a,mins:c,sums:u,tries:f});for(let A of X.ids)f[A]=X.tries[A]}return l.push(R),m.terminate()})}await Promise.all(I);let _=x(p,{fd:p.length<1?1:void 0,flags:"a",highWaterMark:1048576}),M=Buffer.allocUnsafe(100);_.write("{"),S(f,M,l[0],_,", ",E),_.end(`} -`);function E(o,m,D,R){let X=Math.round(u[R<<1]/s[R<<2]);o.write(m.toString("utf8",0,D)),o.write("="),o.write((c[R<<3]/10).toFixed(1)),o.write("/"),o.write((X/10).toFixed(1)),o.write("/"),o.write((a[R<<3]/10).toFixed(1))}}import{createReadStream as Z}from"node:fs";var C=11*48,P=111*48;function q(e,t,r){return e[t]===45?(++t,t+4>r?C-10*e[t]-e[t+2]:P-100*e[t]-10*e[t+1]-e[t+3]):t+4>r?10*e[t]+e[t+2]-C:100*e[t]+10*e[t+1]+e[t+3]-P}async function H({end:e,filePath:t,id:r,start:p,counts:i,maxes:n,mins:c,sums:a}){if(p>=e)return{id:r,trie:g(r,0)};let s=g(r),u=r*1e4+1,f=Buffer.allocUnsafe(107),l=Z(t,{start:p,end:e-1,highWaterMark:w(e-p)}),I=0,_;for await(let o of l){let m=o.length;for(let D=0;D=m?n[o]:m,++i[o>>1],a[o>>2]+=m}return{id:r,trie:s}}function k({a:e,b:t,tries:r,counts:p,maxes:i,mins:n,sums:c}){function a(u,f){u<<=3,f<<=3,n[u]=Math.min(n[u],n[f]),i[u]=Math.max(i[u],i[f]),p[u>>1]+=p[f>>1],c[u>>2]+=c[f>>2]}return{ids:T(r,e,t,a),tries:r}}if(V){let e=F(import.meta.url);O(process.argv[2],e,v())}else b.addListener("message",async e=>{if(e.type==="process")b.postMessage(await H(e));else if(e.type==="merge")b.postMessage(k(e));else throw new Error("Unknown message type")}); +import{availableParallelism as v}from"node:os";import{fileURLToPath as F}from"node:url";import{isMainThread as V,parentPort as b}from"node:worker_threads";import{createWriteStream as x}from"node:fs";import{open as B}from"fs/promises";function h(e,t,r){return e>t?e<=r?e:r:t}async function d(e,t,r,p=0){let i=await B(e);try{let n=(await i.stat()).size,c=Math.max(p,Math.floor(n/t)),a=Buffer.allocUnsafe(r),s=[],u=0;for(let f=c;f=0&&Ie.length&&(e=N(e,n+218)),e[0]+=218,e[i+0]=n,e[n+0]=e[1]),i=n}return[e,i]}function g(e=0,t=655360){t=Math.max(219,t);let r=new Int32Array(new SharedArrayBuffer(t<<2));return r[0]=219,r[1]=e,r}function N(e,t=0){let r=e[0];t=Math.max(t,Math.ceil(r*1.6180339887));let p=new Int32Array(new SharedArrayBuffer(t<<2));for(let i=0;ie[s].length&&(e[s]=N(e[s],o+2),i.add(s)),e[s][0]+=2,e[s][u+0]=o,e[s][o+0]=E,e[s][o+1]=M;else{let m=e[s][o+0];s!==m&&(o=e[s][o+1]),n.push([m,o,E,M])}}u+=1,l+=1}}n.splice(0,c)}while(n.length>0);return Array.from(i)}function S(e,t,r,p,i="",n){let c=new Array(t.length+1);c[0]=[r,3,0];let a=0,s=!1;do{let[u,f,l]=c[a];if(l>=216){--a;continue}c[a][1]+=1,++c[a][2];let I=e[u][f+0];if(I===0)continue;let R=e[u][I+0];u!==R&&(I=e[u][I+1],u=R),t[a]=l+32,c[++a]=[u,I+2,0];let M=e[u][I+1];M!==0&&(s&&p.write(i),s=!0,n(p,t,a,M))}while(a>=0)}import{Worker as W}from"worker_threads";function U(e){let t=new W(e);return t.on("error",r=>{throw r}),t.on("messageerror",r=>{throw r}),t.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${t.threadId} exited with code ${r}`)}),t}function y(e,t){return new Promise(r=>{e.once("message",r),e.postMessage(t)})}async function O(e,t,r,p=""){r=h(r,1,512);let i=await d(e,r,107,16384);r=i.length;let n=new SharedArrayBuffer(1e4*r+1<<4),c=new Int16Array(n),a=new Int16Array(n,2),s=new Uint32Array(n,4),u=new Float64Array(n,8),f=new Array(r),l=[],I=new Array(r);for(let o=0;o{let _=D.id;for(f[D.id]=D.trie;l.length>0;){let X=await y(m,{type:"merge",a:_,b:l.pop(),counts:s,maxes:a,mins:c,sums:u,tries:f});for(let A of X.ids)f[A]=X.tries[A]}return l.push(_),m.terminate()})}await Promise.all(I);let R=x(p,{fd:p.length<1?1:void 0,flags:"a",highWaterMark:1048576}),M=Buffer.allocUnsafe(100);R.write("{"),S(f,M,l[0],R,", ",E),R.end(`} +`);function E(o,m,D,_){let X=Math.round(u[_<<1]/s[_<<2]);o.write(m.toString("utf8",0,D)),o.write("="),o.write((c[_<<3]/10).toFixed(1)),o.write("/"),o.write((X/10).toFixed(1)),o.write("/"),o.write((a[_<<3]/10).toFixed(1))}}import{createReadStream as Z}from"node:fs";var C=11*48,P=111*48;function q(e,t,r){return e[t]===45?(++t,t+4>r?C-10*e[t]-e[t+2]:P-100*e[t]-10*e[t+1]-e[t+3]):t+4>r?10*e[t]+e[t+2]-C:100*e[t]+10*e[t+1]+e[t+3]-P}async function H({end:e,filePath:t,id:r,start:p,counts:i,maxes:n,mins:c,sums:a}){if(p>=e)return{id:r,trie:g(r,0)};let s=g(r),u=r*1e4+1,f=Buffer.allocUnsafe(107),l=Z(t,{start:p,end:e-1,highWaterMark:w(e-p)}),I=0,R;for await(let o of l){let m=o.length;for(let D=0;D=m?n[o]:m,++i[o>>1],a[o>>2]+=m}return{id:r,trie:s}}function k({a:e,b:t,tries:r,counts:p,maxes:i,mins:n,sums:c}){function a(u,f){u<<=3,f<<=3,n[u]=Math.min(n[u],n[f]),i[u]=Math.max(i[u],i[f]),p[u>>1]+=p[f>>1],c[u>>2]+=c[f>>2]}return{ids:T(r,e,t,a),tries:r}}if(V){let e=F(import.meta.url);O(process.argv[2],e,v())}else b.addListener("message",async e=>{if(e.type==="process")b.postMessage(await H(e));else if(e.type==="merge")b.postMessage(k(e));else throw new Error("Unknown message type")}); //# sourceMappingURL=index.mjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index a9dc877..aedda1b 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../src/index.ts", "../src/main.ts", "../src/utils/stream.ts", "../src/utils/utf8Trie.ts", "../src/utils/worker.ts", "../src/worker.ts", "../src/utils/parse.ts"], - "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === \"process\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { WriteStream, createWriteStream } from \"node:fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n BRC.MAX_ENTRY_LEN,\n Config.CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: \"process\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[res.id] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: \"merge\",\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { open } from \"fs/promises\";\n\nimport { Config } from \"../constants/config\";\nimport { CharCode } from \"../constants/utf8\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CharCode.NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= Config.HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, Config.HIGH_WATER_MARK_MIN, Config.HIGH_WATER_MARK_MAX);\n}\n", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.add(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { createReadStream } from \"node:fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * BRC.MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(BRC.MAX_ENTRY_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CharCode.NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 4;\n if (buffer[semI - 2] === CharCode.SEMICOLON) {\n semI -= 2;\n } else if (buffer[semI - 1] === CharCode.SEMICOLON) {\n semI -= 1;\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TrieNodeProto.VALUE_IDX] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf + TrieNodeProto.VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TrieNodeProto.VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], - "mappings": "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", + "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === \"process\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { WriteStream, createWriteStream } from \"node:fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n BRC.MAX_ENTRY_LEN,\n Config.CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: \"process\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[res.id] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: \"merge\",\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { open } from \"fs/promises\";\n\nimport { Config } from \"../constants/config\";\nimport { CharCode } from \"../constants/utf8\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CharCode.NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= Config.HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, Config.HIGH_WATER_MARK_MIN, Config.HIGH_WATER_MARK_MAX);\n}\n", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.add(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { createReadStream } from \"node:fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * BRC.MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(BRC.MAX_ENTRY_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CharCode.NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 5;\n if (buffer[semI] !== CharCode.SEMICOLON) {\n semI += 1 | (1 + ~(buffer[semI - 1] === CharCode.SEMICOLON));\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TrieNodeProto.VALUE_IDX] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf + TrieNodeProto.VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TrieNodeProto.VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], + "mappings": "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", "names": ["availableParallelism", "fileURLToPath", "isMainThread", "parentPort", "createWriteStream", "open", "clamp", "value", "min", "max", "getFileChunks", "filePath", "target", "maxLineLength", "minSize", "file", "open", "size", "chunkSize", "buffer", "chunks", "start", "end", "res", "newline", "getHighWaterMark", "add", "trie", "key", "min", "max", "index", "child", "grow", "createTrie", "id", "size", "trie", "grow", "minSize", "length", "next", "mergeLeft", "tries", "at", "bt", "mergeFn", "grown", "queue", "Q", "q", "ai", "bi", "bvi", "avi", "bn", "ri", "rt", "li", "lt", "print", "key", "trieIndex", "stream", "separator", "callbackFn", "stack", "top", "tail", "trieI", "childPtr", "numChild", "childI", "childTrieI", "valueIndex", "Worker", "createWorker", "workerPath", "worker", "err", "code", "exec", "req", "resolve", "run", "filePath", "workerPath", "maxWorkers", "outPath", "clamp", "chunks", "getFileChunks", "valBuf", "mins", "maxes", "counts", "sums", "tries", "unmerged", "tasks", "i", "worker", "createWorker", "exec", "res", "a", "id", "out", "createWriteStream", "buffer", "print", "printStation", "stream", "name", "nameLen", "vi", "avg", "createReadStream", "CHAR_ZERO_11", "CHAR_ZERO_111", "parseDouble", "b", "min", "max", "run", "end", "filePath", "id", "start", "counts", "maxes", "mins", "sums", "createTrie", "trie", "stations", "buffer", "stream", "createReadStream", "getHighWaterMark", "bufI", "leaf", "chunk", "N", "i", "semI", "tempV", "parseDouble", "add", "updateStation", "newStation", "index", "temp", "merge", "a", "b", "tries", "mergeStations", "ai", "bi", "mergeLeft", "isMainThread", "workerPath", "fileURLToPath", "run", "availableParallelism", "parentPort", "msg", "merge"] } diff --git a/src/main/nodejs/havelessbemore/src/worker.ts b/src/main/nodejs/havelessbemore/src/worker.ts index fc2d680..0908493 100644 --- a/src/main/nodejs/havelessbemore/src/worker.ts +++ b/src/main/nodejs/havelessbemore/src/worker.ts @@ -53,11 +53,9 @@ export async function run({ } // Get semicolon - let semI = bufI - 4; - if (buffer[semI - 2] === CharCode.SEMICOLON) { - semI -= 2; - } else if (buffer[semI - 1] === CharCode.SEMICOLON) { - semI -= 1; + let semI = bufI - 5; + if (buffer[semI] !== CharCode.SEMICOLON) { + semI += 1 | (1 + ~(buffer[semI - 1] === CharCode.SEMICOLON)); } // Get temperature From c2a68a312b32d88dfb5c82a95000a0dcf5c38fb4 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Sun, 26 May 2024 00:50:08 -0400 Subject: [PATCH 49/69] Refactor worker's processing loop --- src/main/nodejs/havelessbemore/README.md | 4 +- src/main/nodejs/havelessbemore/dist/index.mjs | 2 +- .../nodejs/havelessbemore/dist/index.mjs.map | 4 +- src/main/nodejs/havelessbemore/src/worker.ts | 55 ++++++++++--------- 4 files changed, 34 insertions(+), 31 deletions(-) diff --git a/src/main/nodejs/havelessbemore/README.md b/src/main/nodejs/havelessbemore/README.md index ca5ec8c..a143f8a 100644 --- a/src/main/nodejs/havelessbemore/README.md +++ b/src/main/nodejs/havelessbemore/README.md @@ -14,10 +14,10 @@ ### Results -- Min: 13.2s +- Min: 13.0s - Avg: 13.8s - Max: 14.2s -- Samples: 5 consecutive runs +- Samples: 10 runs, 5s apart #### Specs: diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index f8aa95d..31cb891 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -1,3 +1,3 @@ import{availableParallelism as v}from"node:os";import{fileURLToPath as F}from"node:url";import{isMainThread as V,parentPort as b}from"node:worker_threads";import{createWriteStream as x}from"node:fs";import{open as B}from"fs/promises";function h(e,t,r){return e>t?e<=r?e:r:t}async function d(e,t,r,p=0){let i=await B(e);try{let n=(await i.stat()).size,c=Math.max(p,Math.floor(n/t)),a=Buffer.allocUnsafe(r),s=[],u=0;for(let f=c;f=0&&Ie.length&&(e=N(e,n+218)),e[0]+=218,e[i+0]=n,e[n+0]=e[1]),i=n}return[e,i]}function g(e=0,t=655360){t=Math.max(219,t);let r=new Int32Array(new SharedArrayBuffer(t<<2));return r[0]=219,r[1]=e,r}function N(e,t=0){let r=e[0];t=Math.max(t,Math.ceil(r*1.6180339887));let p=new Int32Array(new SharedArrayBuffer(t<<2));for(let i=0;ie[s].length&&(e[s]=N(e[s],o+2),i.add(s)),e[s][0]+=2,e[s][u+0]=o,e[s][o+0]=E,e[s][o+1]=M;else{let m=e[s][o+0];s!==m&&(o=e[s][o+1]),n.push([m,o,E,M])}}u+=1,l+=1}}n.splice(0,c)}while(n.length>0);return Array.from(i)}function S(e,t,r,p,i="",n){let c=new Array(t.length+1);c[0]=[r,3,0];let a=0,s=!1;do{let[u,f,l]=c[a];if(l>=216){--a;continue}c[a][1]+=1,++c[a][2];let I=e[u][f+0];if(I===0)continue;let R=e[u][I+0];u!==R&&(I=e[u][I+1],u=R),t[a]=l+32,c[++a]=[u,I+2,0];let M=e[u][I+1];M!==0&&(s&&p.write(i),s=!0,n(p,t,a,M))}while(a>=0)}import{Worker as W}from"worker_threads";function U(e){let t=new W(e);return t.on("error",r=>{throw r}),t.on("messageerror",r=>{throw r}),t.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${t.threadId} exited with code ${r}`)}),t}function y(e,t){return new Promise(r=>{e.once("message",r),e.postMessage(t)})}async function O(e,t,r,p=""){r=h(r,1,512);let i=await d(e,r,107,16384);r=i.length;let n=new SharedArrayBuffer(1e4*r+1<<4),c=new Int16Array(n),a=new Int16Array(n,2),s=new Uint32Array(n,4),u=new Float64Array(n,8),f=new Array(r),l=[],I=new Array(r);for(let o=0;o{let _=D.id;for(f[D.id]=D.trie;l.length>0;){let X=await y(m,{type:"merge",a:_,b:l.pop(),counts:s,maxes:a,mins:c,sums:u,tries:f});for(let A of X.ids)f[A]=X.tries[A]}return l.push(_),m.terminate()})}await Promise.all(I);let R=x(p,{fd:p.length<1?1:void 0,flags:"a",highWaterMark:1048576}),M=Buffer.allocUnsafe(100);R.write("{"),S(f,M,l[0],R,", ",E),R.end(`} -`);function E(o,m,D,_){let X=Math.round(u[_<<1]/s[_<<2]);o.write(m.toString("utf8",0,D)),o.write("="),o.write((c[_<<3]/10).toFixed(1)),o.write("/"),o.write((X/10).toFixed(1)),o.write("/"),o.write((a[_<<3]/10).toFixed(1))}}import{createReadStream as Z}from"node:fs";var C=11*48,P=111*48;function q(e,t,r){return e[t]===45?(++t,t+4>r?C-10*e[t]-e[t+2]:P-100*e[t]-10*e[t+1]-e[t+3]):t+4>r?10*e[t]+e[t+2]-C:100*e[t]+10*e[t+1]+e[t+3]-P}async function H({end:e,filePath:t,id:r,start:p,counts:i,maxes:n,mins:c,sums:a}){if(p>=e)return{id:r,trie:g(r,0)};let s=g(r),u=r*1e4+1,f=Buffer.allocUnsafe(107),l=Z(t,{start:p,end:e-1,highWaterMark:w(e-p)}),I=0,R;for await(let o of l){let m=o.length;for(let D=0;D=m?n[o]:m,++i[o>>1],a[o>>2]+=m}return{id:r,trie:s}}function k({a:e,b:t,tries:r,counts:p,maxes:i,mins:n,sums:c}){function a(u,f){u<<=3,f<<=3,n[u]=Math.min(n[u],n[f]),i[u]=Math.max(i[u],i[f]),p[u>>1]+=p[f>>1],c[u>>2]+=c[f>>2]}return{ids:T(r,e,t,a),tries:r}}if(V){let e=F(import.meta.url);O(process.argv[2],e,v())}else b.addListener("message",async e=>{if(e.type==="process")b.postMessage(await H(e));else if(e.type==="merge")b.postMessage(k(e));else throw new Error("Unknown message type")}); +`);function E(o,m,D,_){let X=Math.round(u[_<<1]/s[_<<2]);o.write(m.toString("utf8",0,D)),o.write("="),o.write((c[_<<3]/10).toFixed(1)),o.write("/"),o.write((X/10).toFixed(1)),o.write("/"),o.write((a[_<<3]/10).toFixed(1))}}import{createReadStream as Z}from"node:fs";var C=11*48,P=111*48;function q(e,t,r){return e[t]===45?(++t,t+4>r?C-10*e[t]-e[t+2]:P-100*e[t]-10*e[t+1]-e[t+3]):t+4>r?10*e[t]+e[t+2]-C:100*e[t]+10*e[t+1]+e[t+3]-P}async function H({end:e,filePath:t,id:r,start:p,counts:i,maxes:n,mins:c,sums:a}){if(p>=e)return{id:r,trie:g(r,0)};let s=g(r),u=r*1e4+1,f=Buffer.allocUnsafe(107),l=Z(t,{start:p,end:e-1,highWaterMark:w(e-p)}),I=-1,R;for await(let o of l){let m=o.length;for(let D=0;D=m?n[o]:m,++i[o>>1],a[o>>2]+=m}return{id:r,trie:s}}function k({a:e,b:t,tries:r,counts:p,maxes:i,mins:n,sums:c}){function a(u,f){u<<=3,f<<=3,n[u]=Math.min(n[u],n[f]),i[u]=Math.max(i[u],i[f]),p[u>>1]+=p[f>>1],c[u>>2]+=c[f>>2]}return{ids:T(r,e,t,a),tries:r}}if(V){let e=F(import.meta.url);O(process.argv[2],e,v())}else b.addListener("message",async e=>{if(e.type==="process")b.postMessage(await H(e));else if(e.type==="merge")b.postMessage(k(e));else throw new Error("Unknown message type")}); //# sourceMappingURL=index.mjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index aedda1b..330dd61 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../src/index.ts", "../src/main.ts", "../src/utils/stream.ts", "../src/utils/utf8Trie.ts", "../src/utils/worker.ts", "../src/worker.ts", "../src/utils/parse.ts"], - "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === \"process\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { WriteStream, createWriteStream } from \"node:fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n BRC.MAX_ENTRY_LEN,\n Config.CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: \"process\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[res.id] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: \"merge\",\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { open } from \"fs/promises\";\n\nimport { Config } from \"../constants/config\";\nimport { CharCode } from \"../constants/utf8\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CharCode.NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= Config.HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, Config.HIGH_WATER_MARK_MIN, Config.HIGH_WATER_MARK_MAX);\n}\n", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.add(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { createReadStream } from \"node:fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * BRC.MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(BRC.MAX_ENTRY_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = 0;\n let leaf: number;\n for await (const chunk of stream) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // If not newline\n if (chunk[i] !== CharCode.NEWLINE) {\n buffer[bufI++] = chunk[i];\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 5;\n if (buffer[semI] !== CharCode.SEMICOLON) {\n semI += 1 | (1 + ~(buffer[semI - 1] === CharCode.SEMICOLON));\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = 0;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TrieNodeProto.VALUE_IDX] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf + TrieNodeProto.VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TrieNodeProto.VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], - "mappings": "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", + "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === \"process\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { WriteStream, createWriteStream } from \"node:fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n BRC.MAX_ENTRY_LEN,\n Config.CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: \"process\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[res.id] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: \"merge\",\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { open } from \"fs/promises\";\n\nimport { Config } from \"../constants/config\";\nimport { CharCode } from \"../constants/utf8\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CharCode.NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= Config.HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, Config.HIGH_WATER_MARK_MIN, Config.HIGH_WATER_MARK_MAX);\n}\n", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.add(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { createReadStream } from \"node:fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * BRC.MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(BRC.MAX_ENTRY_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = -1;\n let leaf: number;\n for await (const chunk of stream) {\n\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n \n // Add byte to buffer\n buffer[++bufI] = chunk[i];\n\n // If newline\n if (chunk[i] === CharCode.NEWLINE) {\n\n // Get semicolon\n let semI = bufI - 5;\n if (buffer[semI] !== CharCode.SEMICOLON) {\n semI += 1 | (1 + ~(buffer[semI - 1] === CharCode.SEMICOLON));\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = -1;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TrieNodeProto.VALUE_IDX] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf + TrieNodeProto.VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TrieNodeProto.VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], + "mappings": "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", "names": ["availableParallelism", "fileURLToPath", "isMainThread", "parentPort", "createWriteStream", "open", "clamp", "value", "min", "max", "getFileChunks", "filePath", "target", "maxLineLength", "minSize", "file", "open", "size", "chunkSize", "buffer", "chunks", "start", "end", "res", "newline", "getHighWaterMark", "add", "trie", "key", "min", "max", "index", "child", "grow", "createTrie", "id", "size", "trie", "grow", "minSize", "length", "next", "mergeLeft", "tries", "at", "bt", "mergeFn", "grown", "queue", "Q", "q", "ai", "bi", "bvi", "avi", "bn", "ri", "rt", "li", "lt", "print", "key", "trieIndex", "stream", "separator", "callbackFn", "stack", "top", "tail", "trieI", "childPtr", "numChild", "childI", "childTrieI", "valueIndex", "Worker", "createWorker", "workerPath", "worker", "err", "code", "exec", "req", "resolve", "run", "filePath", "workerPath", "maxWorkers", "outPath", "clamp", "chunks", "getFileChunks", "valBuf", "mins", "maxes", "counts", "sums", "tries", "unmerged", "tasks", "i", "worker", "createWorker", "exec", "res", "a", "id", "out", "createWriteStream", "buffer", "print", "printStation", "stream", "name", "nameLen", "vi", "avg", "createReadStream", "CHAR_ZERO_11", "CHAR_ZERO_111", "parseDouble", "b", "min", "max", "run", "end", "filePath", "id", "start", "counts", "maxes", "mins", "sums", "createTrie", "trie", "stations", "buffer", "stream", "createReadStream", "getHighWaterMark", "bufI", "leaf", "chunk", "N", "i", "semI", "tempV", "parseDouble", "add", "updateStation", "newStation", "index", "temp", "merge", "a", "b", "tries", "mergeStations", "ai", "bi", "mergeLeft", "isMainThread", "workerPath", "fileURLToPath", "run", "availableParallelism", "parentPort", "msg", "merge"] } diff --git a/src/main/nodejs/havelessbemore/src/worker.ts b/src/main/nodejs/havelessbemore/src/worker.ts index 0908493..64ec3b9 100644 --- a/src/main/nodejs/havelessbemore/src/worker.ts +++ b/src/main/nodejs/havelessbemore/src/worker.ts @@ -40,39 +40,42 @@ export async function run({ }); // For each chunk - let bufI = 0; + let bufI = -1; let leaf: number; for await (const chunk of stream) { + // For each byte const N = chunk.length; for (let i = 0; i < N; ++i) { - // If not newline - if (chunk[i] !== CharCode.NEWLINE) { - buffer[bufI++] = chunk[i]; - continue; - } + + // Add byte to buffer + buffer[++bufI] = chunk[i]; - // Get semicolon - let semI = bufI - 5; - if (buffer[semI] !== CharCode.SEMICOLON) { - semI += 1 | (1 + ~(buffer[semI - 1] === CharCode.SEMICOLON)); - } + // If newline + if (chunk[i] === CharCode.NEWLINE) { + + // Get semicolon + let semI = bufI - 5; + if (buffer[semI] !== CharCode.SEMICOLON) { + semI += 1 | (1 + ~(buffer[semI - 1] === CharCode.SEMICOLON)); + } + + // Get temperature + const tempV = parseDouble(buffer, semI + 1, bufI); + bufI = -1; + + // Add the station's name to the trie and get leaf index + [trie, leaf] = add(trie, buffer, 0, semI); - // Get temperature - const tempV = parseDouble(buffer, semI + 1, bufI); - bufI = 0; - - // Add the station's name to the trie and get leaf index - [trie, leaf] = add(trie, buffer, 0, semI); - - // If the station existed - if (trie[leaf + TrieNodeProto.VALUE_IDX] !== Trie.NULL) { - // Update the station's value - updateStation(trie[leaf + TrieNodeProto.VALUE_IDX], tempV); - } else { - // Add the new station's value - trie[leaf + TrieNodeProto.VALUE_IDX] = stations; - newStation(stations++, tempV); + // If the station existed + if (trie[leaf + TrieNodeProto.VALUE_IDX] !== Trie.NULL) { + // Update the station's value + updateStation(trie[leaf + TrieNodeProto.VALUE_IDX], tempV); + } else { + // Add the new station's value + trie[leaf + TrieNodeProto.VALUE_IDX] = stations; + newStation(stations++, tempV); + } } } } From 38fd452dce8a2bd13be339c18861a02b35e6adeb Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Sun, 26 May 2024 00:54:07 -0400 Subject: [PATCH 50/69] Remove unused NOTICE file, Add '' to package.json --- src/main/nodejs/havelessbemore/NOTICE | 23 --------------------- src/main/nodejs/havelessbemore/package.json | 1 + 2 files changed, 1 insertion(+), 23 deletions(-) delete mode 100644 src/main/nodejs/havelessbemore/NOTICE diff --git a/src/main/nodejs/havelessbemore/NOTICE b/src/main/nodejs/havelessbemore/NOTICE deleted file mode 100644 index 1614c55..0000000 --- a/src/main/nodejs/havelessbemore/NOTICE +++ /dev/null @@ -1,23 +0,0 @@ -<%= pkg.homepage %> - -MIT License - -Copyright (C) 2024-<%= moment().format('YYYY') %> <%= pkg.author %> - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/package.json b/src/main/nodejs/havelessbemore/package.json index f9b63c2..48c845f 100644 --- a/src/main/nodejs/havelessbemore/package.json +++ b/src/main/nodejs/havelessbemore/package.json @@ -1,4 +1,5 @@ { + "$schema": "http://json.schemastore.org/package", "description": "Submission for the One Billion Row Challenge", "license": "MIT", "author": "Michael Rojas (https://github.com/havelessbemore)", From 195220886c7dbe891463f43e0cefb9b64d520fa9 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Sun, 26 May 2024 02:54:43 -0400 Subject: [PATCH 51/69] Open file once and share fd with workers --- src/main/nodejs/havelessbemore/dist/index.mjs | 4 +- .../nodejs/havelessbemore/dist/index.mjs.map | 6 +- src/main/nodejs/havelessbemore/src/main.ts | 14 +++- .../src/types/processRequest.ts | 2 +- .../nodejs/havelessbemore/src/utils/stream.ts | 67 +++++++++---------- .../nodejs/havelessbemore/src/utils/worker.ts | 2 +- src/main/nodejs/havelessbemore/src/worker.ts | 15 ++--- 7 files changed, 55 insertions(+), 55 deletions(-) diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index 31cb891..875863e 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -1,3 +1,3 @@ -import{availableParallelism as v}from"node:os";import{fileURLToPath as F}from"node:url";import{isMainThread as V,parentPort as b}from"node:worker_threads";import{createWriteStream as x}from"node:fs";import{open as B}from"fs/promises";function h(e,t,r){return e>t?e<=r?e:r:t}async function d(e,t,r,p=0){let i=await B(e);try{let n=(await i.stat()).size,c=Math.max(p,Math.floor(n/t)),a=Buffer.allocUnsafe(r),s=[],u=0;for(let f=c;f=0&&Ie.length&&(e=N(e,n+218)),e[0]+=218,e[i+0]=n,e[n+0]=e[1]),i=n}return[e,i]}function g(e=0,t=655360){t=Math.max(219,t);let r=new Int32Array(new SharedArrayBuffer(t<<2));return r[0]=219,r[1]=e,r}function N(e,t=0){let r=e[0];t=Math.max(t,Math.ceil(r*1.6180339887));let p=new Int32Array(new SharedArrayBuffer(t<<2));for(let i=0;ie[s].length&&(e[s]=N(e[s],o+2),i.add(s)),e[s][0]+=2,e[s][u+0]=o,e[s][o+0]=E,e[s][o+1]=M;else{let m=e[s][o+0];s!==m&&(o=e[s][o+1]),n.push([m,o,E,M])}}u+=1,l+=1}}n.splice(0,c)}while(n.length>0);return Array.from(i)}function S(e,t,r,p,i="",n){let c=new Array(t.length+1);c[0]=[r,3,0];let a=0,s=!1;do{let[u,f,l]=c[a];if(l>=216){--a;continue}c[a][1]+=1,++c[a][2];let I=e[u][f+0];if(I===0)continue;let R=e[u][I+0];u!==R&&(I=e[u][I+1],u=R),t[a]=l+32,c[++a]=[u,I+2,0];let M=e[u][I+1];M!==0&&(s&&p.write(i),s=!0,n(p,t,a,M))}while(a>=0)}import{Worker as W}from"worker_threads";function U(e){let t=new W(e);return t.on("error",r=>{throw r}),t.on("messageerror",r=>{throw r}),t.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${t.threadId} exited with code ${r}`)}),t}function y(e,t){return new Promise(r=>{e.once("message",r),e.postMessage(t)})}async function O(e,t,r,p=""){r=h(r,1,512);let i=await d(e,r,107,16384);r=i.length;let n=new SharedArrayBuffer(1e4*r+1<<4),c=new Int16Array(n),a=new Int16Array(n,2),s=new Uint32Array(n,4),u=new Float64Array(n,8),f=new Array(r),l=[],I=new Array(r);for(let o=0;o{let _=D.id;for(f[D.id]=D.trie;l.length>0;){let X=await y(m,{type:"merge",a:_,b:l.pop(),counts:s,maxes:a,mins:c,sums:u,tries:f});for(let A of X.ids)f[A]=X.tries[A]}return l.push(_),m.terminate()})}await Promise.all(I);let R=x(p,{fd:p.length<1?1:void 0,flags:"a",highWaterMark:1048576}),M=Buffer.allocUnsafe(100);R.write("{"),S(f,M,l[0],R,", ",E),R.end(`} -`);function E(o,m,D,_){let X=Math.round(u[_<<1]/s[_<<2]);o.write(m.toString("utf8",0,D)),o.write("="),o.write((c[_<<3]/10).toFixed(1)),o.write("/"),o.write((X/10).toFixed(1)),o.write("/"),o.write((a[_<<3]/10).toFixed(1))}}import{createReadStream as Z}from"node:fs";var C=11*48,P=111*48;function q(e,t,r){return e[t]===45?(++t,t+4>r?C-10*e[t]-e[t+2]:P-100*e[t]-10*e[t+1]-e[t+3]):t+4>r?10*e[t]+e[t+2]-C:100*e[t]+10*e[t+1]+e[t+3]-P}async function H({end:e,filePath:t,id:r,start:p,counts:i,maxes:n,mins:c,sums:a}){if(p>=e)return{id:r,trie:g(r,0)};let s=g(r),u=r*1e4+1,f=Buffer.allocUnsafe(107),l=Z(t,{start:p,end:e-1,highWaterMark:w(e-p)}),I=-1,R;for await(let o of l){let m=o.length;for(let D=0;D=m?n[o]:m,++i[o>>1],a[o>>2]+=m}return{id:r,trie:s}}function k({a:e,b:t,tries:r,counts:p,maxes:i,mins:n,sums:c}){function a(u,f){u<<=3,f<<=3,n[u]=Math.min(n[u],n[f]),i[u]=Math.max(i[u],i[f]),p[u>>1]+=p[f>>1],c[u>>2]+=c[f>>2]}return{ids:T(r,e,t,a),tries:r}}if(V){let e=F(import.meta.url);O(process.argv[2],e,v())}else b.addListener("message",async e=>{if(e.type==="process")b.postMessage(await H(e));else if(e.type==="merge")b.postMessage(k(e));else throw new Error("Unknown message type")}); +import{availableParallelism as V}from"node:os";import{fileURLToPath as K}from"node:url";import{isMainThread as G,parentPort as b}from"node:worker_threads";import{createWriteStream as x}from"node:fs";import{open as Z}from"node:fs/promises";import{stdout as v}from"node:process";function d(e,t,r){return e>t?e<=r?e:r:t}async function w(e,t,r,I=0){let u=(await e.stat()).size,f=Math.max(I,Math.floor(u/t)),p=Buffer.allocUnsafe(r),a=[],n=0;for(let o=f;o=0&&me.length&&(e=T(e,f+218)),e[0]+=218,e[u+0]=f,e[f+0]=e[1]),u=f}return[e,u]}function g(e=0,t=655360){t=Math.max(219,t);let r=new Int32Array(new SharedArrayBuffer(t<<2));return r[0]=219,r[1]=e,r}function T(e,t=0){let r=e[0];t=Math.max(t,Math.ceil(r*1.6180339887));let I=new Int32Array(new SharedArrayBuffer(t<<2));for(let u=0;ue[n].length&&(e[n]=T(e[n],s+2),u.add(n)),e[n][0]+=2,e[n][o+0]=s,e[n][s+0]=h,e[n][s+1]=M;else{let i=e[n][s+0];n!==i&&(s=e[n][s+1]),f.push([i,s,h,M])}}o+=1,m+=1}}f.splice(0,p)}while(f.length>0);return Array.from(u)}function U(e,t,r,I,u="",f){let p=new Array(t.length+1);p[0]=[r,3,0];let a=0,n=!1;do{let[o,c,m]=p[a];if(m>=216){--a;continue}p[a][1]+=1,++p[a][2];let l=e[o][c+0];if(l===0)continue;let R=e[o][l+0];o!==R&&(l=e[o][l+1],o=R),t[a]=m+32,p[++a]=[o,l+2,0];let M=e[o][l+1];M!==0&&(n&&I.write(u),n=!0,f(I,t,a,M))}while(a>=0)}import{Worker as W}from"node:worker_threads";function O(e){let t=new W(e);return t.on("error",r=>{throw r}),t.on("messageerror",r=>{throw r}),t.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${t.threadId} exited with code ${r}`)}),t}function y(e,t){return new Promise(r=>{e.once("message",r),e.postMessage(t)})}async function C(e,t,r,I=""){r=d(r,1,512);let u=await Z(e,"r"),f=await w(u,r,107,16384);r=f.length;let p=new SharedArrayBuffer(1e4*r+1<<4),a=new Int16Array(p),n=new Int16Array(p,2),o=new Uint32Array(p,4),c=new Float64Array(p,8),m=new Array(r),l=[],R=new Array(r);for(let i=0;i{let E=_.id;for(m[_.id]=_.trie;l.length>0;){let X=await y(D,{type:"merge",a:E,b:l.pop(),counts:o,maxes:n,mins:a,sums:c,tries:m});for(let A of X.ids)m[A]=X.tries[A]}return l.push(E),D.terminate()})}await Promise.all(R),await u.close();let M=x(I,{fd:I.length<1?v.fd:void 0,flags:"a",highWaterMark:1048576}),h=Buffer.allocUnsafe(100);M.write("{"),U(m,h,l[0],M,", ",s),M.end(`} +`);function s(i,D,_,E){let X=Math.round(c[E<<1]/o[E<<2]);i.write(D.toString("utf8",0,_)),i.write("="),i.write((a[E<<3]/10).toFixed(1)),i.write("/"),i.write((X/10).toFixed(1)),i.write("/"),i.write((n[E<<3]/10).toFixed(1))}}import{createReadStream as F}from"node:fs";var P=11*48,q=111*48;function H(e,t,r){return e[t]===45?(++t,t+4>r?P-10*e[t]-e[t+2]:q-100*e[t]-10*e[t+1]-e[t+3]):t+4>r?10*e[t]+e[t+2]-P:100*e[t]+10*e[t+1]+e[t+3]-q}async function k({end:e,fd:t,id:r,start:I,counts:u,maxes:f,mins:p,sums:a}){if(I>=e)return{id:r,trie:g(r,0)};let n=g(r),o=r*1e4+1,c=Buffer.allocUnsafe(107),m={autoClose:!1,fd:t,start:I,end:e-1,highWaterMark:L(e-I)},l=-1,R;for await(let s of F("",m)){let i=s.length;for(let D=0;D=i?f[s]:i,++u[s>>1],a[s>>2]+=i}return{id:r,trie:n}}function B({a:e,b:t,tries:r,counts:I,maxes:u,mins:f,sums:p}){function a(o,c){o<<=3,c<<=3,f[o]=Math.min(f[o],f[c]),u[o]=Math.max(u[o],u[c]),I[o>>1]+=I[c>>1],p[o>>2]+=p[c>>2]}return{ids:S(r,e,t,a),tries:r}}if(G){let e=K(import.meta.url);C(process.argv[2],e,V())}else b.addListener("message",async e=>{if(e.type==="process")b.postMessage(await k(e));else if(e.type==="merge")b.postMessage(B(e));else throw new Error("Unknown message type")}); //# sourceMappingURL=index.mjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index 330dd61..cfe26a2 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../src/index.ts", "../src/main.ts", "../src/utils/stream.ts", "../src/utils/utf8Trie.ts", "../src/utils/worker.ts", "../src/worker.ts", "../src/utils/parse.ts"], - "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === \"process\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { WriteStream, createWriteStream } from \"node:fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n filePath,\n maxWorkers,\n BRC.MAX_ENTRY_LEN,\n Config.CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: \"process\",\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[res.id] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: \"merge\",\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? 1 : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { open } from \"fs/promises\";\n\nimport { Config } from \"../constants/config\";\nimport { CharCode } from \"../constants/utf8\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n filePath: string,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Open the given file\n const file = await open(filePath);\n try {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CharCode.NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n } finally {\n // Always close the file before returning\n await file.close();\n }\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= Config.HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, Config.HIGH_WATER_MARK_MIN, Config.HIGH_WATER_MARK_MAX);\n}\n", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.add(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { createReadStream } from \"node:fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * BRC.MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(BRC.MAX_ENTRY_LEN);\n\n // Create the chunk stream\n const stream = createReadStream(filePath, {\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n });\n\n // For each chunk\n let bufI = -1;\n let leaf: number;\n for await (const chunk of stream) {\n\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n \n // Add byte to buffer\n buffer[++bufI] = chunk[i];\n\n // If newline\n if (chunk[i] === CharCode.NEWLINE) {\n\n // Get semicolon\n let semI = bufI - 5;\n if (buffer[semI] !== CharCode.SEMICOLON) {\n semI += 1 | (1 + ~(buffer[semI - 1] === CharCode.SEMICOLON));\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = -1;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TrieNodeProto.VALUE_IDX] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf + TrieNodeProto.VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TrieNodeProto.VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], - "mappings": "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", - "names": ["availableParallelism", "fileURLToPath", "isMainThread", "parentPort", "createWriteStream", "open", "clamp", "value", "min", "max", "getFileChunks", "filePath", "target", "maxLineLength", "minSize", "file", "open", "size", "chunkSize", "buffer", "chunks", "start", "end", "res", "newline", "getHighWaterMark", "add", "trie", "key", "min", "max", "index", "child", "grow", "createTrie", "id", "size", "trie", "grow", "minSize", "length", "next", "mergeLeft", "tries", "at", "bt", "mergeFn", "grown", "queue", "Q", "q", "ai", "bi", "bvi", "avi", "bn", "ri", "rt", "li", "lt", "print", "key", "trieIndex", "stream", "separator", "callbackFn", "stack", "top", "tail", "trieI", "childPtr", "numChild", "childI", "childTrieI", "valueIndex", "Worker", "createWorker", "workerPath", "worker", "err", "code", "exec", "req", "resolve", "run", "filePath", "workerPath", "maxWorkers", "outPath", "clamp", "chunks", "getFileChunks", "valBuf", "mins", "maxes", "counts", "sums", "tries", "unmerged", "tasks", "i", "worker", "createWorker", "exec", "res", "a", "id", "out", "createWriteStream", "buffer", "print", "printStation", "stream", "name", "nameLen", "vi", "avg", "createReadStream", "CHAR_ZERO_11", "CHAR_ZERO_111", "parseDouble", "b", "min", "max", "run", "end", "filePath", "id", "start", "counts", "maxes", "mins", "sums", "createTrie", "trie", "stations", "buffer", "stream", "createReadStream", "getHighWaterMark", "bufI", "leaf", "chunk", "N", "i", "semI", "tempV", "parseDouble", "add", "updateStation", "newStation", "index", "temp", "merge", "a", "b", "tries", "mergeStations", "ai", "bi", "mergeLeft", "isMainThread", "workerPath", "fileURLToPath", "run", "availableParallelism", "parentPort", "msg", "merge"] + "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === \"process\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { WriteStream, createWriteStream } from \"node:fs\";\nimport { open } from \"node:fs/promises\";\nimport { stdout } from \"node:process\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Open the given file\n const file = await open(filePath, \"r\");\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n file,\n maxWorkers,\n BRC.MAX_ENTRY_LEN,\n Config.CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: \"process\",\n counts,\n end: chunks[i][1],\n fd: file.fd,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[res.id] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: \"merge\",\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Close the file\n await file.close();\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? stdout.fd : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { FileHandle } from \"fs/promises\";\n\nimport { Config } from \"../constants/config\";\nimport { CharCode } from \"../constants/utf8\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n file: FileHandle,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CharCode.NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= Config.HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, Config.HIGH_WATER_MARK_MIN, Config.HIGH_WATER_MARK_MAX);\n}\n", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.add(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"node:worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { createReadStream } from \"node:fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n fd,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * BRC.MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(BRC.MAX_ENTRY_LEN);\n\n // Create readstream options\n const opts = {\n autoClose: false,\n fd,\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n };\n\n // For each chunk\n let bufI = -1;\n let leaf: number;\n for await (const chunk of createReadStream(\"\", opts)) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // Add byte to buffer\n buffer[++bufI] = chunk[i];\n\n // If newline\n if (chunk[i] === CharCode.NEWLINE) {\n // Get semicolon\n let semI = bufI - 5;\n if (buffer[semI] !== CharCode.SEMICOLON) {\n semI += 1 | (1 + ~(buffer[semI - 1] === CharCode.SEMICOLON));\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = -1;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TrieNodeProto.VALUE_IDX] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf + TrieNodeProto.VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TrieNodeProto.VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], + "mappings": "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", + "names": ["availableParallelism", "fileURLToPath", "isMainThread", "parentPort", "createWriteStream", "open", "stdout", "clamp", "value", "min", "max", "getFileChunks", "file", "target", "maxLineLength", "minSize", "size", "chunkSize", "buffer", "chunks", "start", "end", "res", "newline", "getHighWaterMark", "add", "trie", "key", "min", "max", "index", "child", "grow", "createTrie", "id", "size", "trie", "grow", "minSize", "length", "next", "i", "mergeLeft", "tries", "at", "bt", "mergeFn", "grown", "queue", "Q", "q", "ai", "bi", "bvi", "avi", "bn", "ri", "rt", "li", "lt", "print", "key", "trieIndex", "stream", "separator", "callbackFn", "stack", "top", "tail", "trieI", "childPtr", "numChild", "childI", "childTrieI", "valueIndex", "Worker", "createWorker", "workerPath", "worker", "err", "code", "exec", "req", "resolve", "run", "filePath", "workerPath", "maxWorkers", "outPath", "clamp", "file", "open", "chunks", "getFileChunks", "valBuf", "mins", "maxes", "counts", "sums", "tries", "unmerged", "tasks", "worker", "createWorker", "exec", "res", "a", "id", "out", "createWriteStream", "stdout", "buffer", "print", "printStation", "stream", "name", "nameLen", "vi", "avg", "createReadStream", "CHAR_ZERO_11", "CHAR_ZERO_111", "parseDouble", "b", "min", "max", "run", "end", "fd", "id", "start", "counts", "maxes", "mins", "sums", "createTrie", "trie", "stations", "buffer", "opts", "getHighWaterMark", "bufI", "leaf", "chunk", "createReadStream", "N", "i", "semI", "tempV", "parseDouble", "add", "updateStation", "newStation", "index", "temp", "merge", "a", "b", "tries", "mergeStations", "ai", "bi", "mergeLeft", "isMainThread", "workerPath", "fileURLToPath", "run", "availableParallelism", "parentPort", "msg", "merge"] } diff --git a/src/main/nodejs/havelessbemore/src/main.ts b/src/main/nodejs/havelessbemore/src/main.ts index 133a1ab..bd01d82 100644 --- a/src/main/nodejs/havelessbemore/src/main.ts +++ b/src/main/nodejs/havelessbemore/src/main.ts @@ -1,4 +1,6 @@ import { WriteStream, createWriteStream } from "node:fs"; +import { open } from "node:fs/promises"; +import { stdout } from "node:process"; import type { MergeRequest } from "./types/mergeRequest"; import type { MergeResponse } from "./types/mergeResponse"; @@ -20,9 +22,12 @@ export async function run( // Sanitize number of workers maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX); + // Open the given file + const file = await open(filePath, "r"); + // Split the file into chunks. Creates 1 or fewer chunks per worker const chunks = await getFileChunks( - filePath, + file, maxWorkers, BRC.MAX_ENTRY_LEN, Config.CHUNK_SIZE_MIN, @@ -52,7 +57,7 @@ export async function run( type: "process", counts, end: chunks[i][1], - filePath, + fd: file.fd, id: i, maxes, mins, @@ -88,9 +93,12 @@ export async function run( // Wait for completion await Promise.all(tasks); + // Close the file + await file.close(); + // Print results const out = createWriteStream(outPath, { - fd: outPath.length < 1 ? 1 : undefined, + fd: outPath.length < 1 ? stdout.fd : undefined, flags: "a", highWaterMark: Config.HIGH_WATER_MARK_OUT, }); diff --git a/src/main/nodejs/havelessbemore/src/types/processRequest.ts b/src/main/nodejs/havelessbemore/src/types/processRequest.ts index 6fa5087..a4e09bf 100644 --- a/src/main/nodejs/havelessbemore/src/types/processRequest.ts +++ b/src/main/nodejs/havelessbemore/src/types/processRequest.ts @@ -3,7 +3,7 @@ import { Request } from "./request"; export interface ProcessRequest extends Request { type: "process"; end: number; - filePath: string; + fd: number; id: number; start: number; // Shared memory diff --git a/src/main/nodejs/havelessbemore/src/utils/stream.ts b/src/main/nodejs/havelessbemore/src/utils/stream.ts index 5d1a380..6bb3565 100644 --- a/src/main/nodejs/havelessbemore/src/utils/stream.ts +++ b/src/main/nodejs/havelessbemore/src/utils/stream.ts @@ -1,4 +1,4 @@ -import { open } from "fs/promises"; +import { FileHandle } from "fs/promises"; import { Config } from "../constants/config"; import { CharCode } from "../constants/utf8"; @@ -35,48 +35,41 @@ export function clamp(value: number, min: number, max: number): number { * @throws Will throw an error if the file cannot be opened or read. */ export async function getFileChunks( - filePath: string, + file: FileHandle, target: number, maxLineLength: number, minSize = 0, ): Promise<[number, number][]> { - // Open the given file - const file = await open(filePath); - try { - // Get the file's size - const size = (await file.stat()).size; - // Calculate each chunk's target size - const chunkSize = Math.max(minSize, Math.floor(size / target)); - // Initialize constants - const buffer = Buffer.allocUnsafe(maxLineLength); - const chunks: [number, number][] = []; - // Traverse the file, visiting each chunk's end index (exclusive) - let start = 0; - for (let end = chunkSize; end < size; end += chunkSize) { - // Read a line at the intended end index - const res = await file.read(buffer, 0, maxLineLength, end); - // Find the nearest newline ('\n') character - const newline = buffer.indexOf(CharCode.NEWLINE); - // If found - if (newline >= 0 && newline < res.bytesRead) { - // Align end with the newline - end += newline + 1; - // Add the chunk - chunks.push([start, end]); - // Update the start index for the next chunk - start = end; - } + // Get the file's size + const size = (await file.stat()).size; + // Calculate each chunk's target size + const chunkSize = Math.max(minSize, Math.floor(size / target)); + // Initialize constants + const buffer = Buffer.allocUnsafe(maxLineLength); + const chunks: [number, number][] = []; + // Traverse the file, visiting each chunk's end index (exclusive) + let start = 0; + for (let end = chunkSize; end < size; end += chunkSize) { + // Read a line at the intended end index + const res = await file.read(buffer, 0, maxLineLength, end); + // Find the nearest newline ('\n') character + const newline = buffer.indexOf(CharCode.NEWLINE); + // If found + if (newline >= 0 && newline < res.bytesRead) { + // Align end with the newline + end += newline + 1; + // Add the chunk + chunks.push([start, end]); + // Update the start index for the next chunk + start = end; } - // Add the last chunk, if necessary - if (start < size) { - chunks.push([start, size]); - } - // Return chunks - return chunks; - } finally { - // Always close the file before returning - await file.close(); } + // Add the last chunk, if necessary + if (start < size) { + chunks.push([start, size]); + } + // Return chunks + return chunks; } /** diff --git a/src/main/nodejs/havelessbemore/src/utils/worker.ts b/src/main/nodejs/havelessbemore/src/utils/worker.ts index 2afce03..cc46254 100644 --- a/src/main/nodejs/havelessbemore/src/utils/worker.ts +++ b/src/main/nodejs/havelessbemore/src/utils/worker.ts @@ -1,4 +1,4 @@ -import { Worker } from "worker_threads"; +import { Worker } from "node:worker_threads"; /** * Creates a new Worker instance. diff --git a/src/main/nodejs/havelessbemore/src/worker.ts b/src/main/nodejs/havelessbemore/src/worker.ts index 64ec3b9..7188aad 100644 --- a/src/main/nodejs/havelessbemore/src/worker.ts +++ b/src/main/nodejs/havelessbemore/src/worker.ts @@ -13,7 +13,7 @@ import { add, createTrie, mergeLeft } from "./utils/utf8Trie"; export async function run({ end, - filePath, + fd, id, start, // Shared memory @@ -32,28 +32,27 @@ export async function run({ let stations = id * BRC.MAX_STATIONS + 1; const buffer = Buffer.allocUnsafe(BRC.MAX_ENTRY_LEN); - // Create the chunk stream - const stream = createReadStream(filePath, { + // Create readstream options + const opts = { + autoClose: false, + fd, start, end: end - 1, highWaterMark: getHighWaterMark(end - start), - }); + }; // For each chunk let bufI = -1; let leaf: number; - for await (const chunk of stream) { - + for await (const chunk of createReadStream("", opts)) { // For each byte const N = chunk.length; for (let i = 0; i < N; ++i) { - // Add byte to buffer buffer[++bufI] = chunk[i]; // If newline if (chunk[i] === CharCode.NEWLINE) { - // Get semicolon let semI = bufI - 5; if (buffer[semI] !== CharCode.SEMICOLON) { From ea182b05f2999401df7c61b8a2e1801262615e86 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Sun, 26 May 2024 14:54:57 -0400 Subject: [PATCH 52/69] Change message type from strings to numbers, Refactor mergeLeft() function --- src/main/nodejs/havelessbemore/dist/index.mjs | 4 ++-- src/main/nodejs/havelessbemore/dist/index.mjs.map | 4 ++-- .../nodejs/havelessbemore/src/constants/utf8.ts | 15 ++++++++++----- src/main/nodejs/havelessbemore/src/index.ts | 6 +++--- src/main/nodejs/havelessbemore/src/main.ts | 5 +++-- .../havelessbemore/src/types/mergeRequest.ts | 4 ++-- .../havelessbemore/src/types/processRequest.ts | 4 ++-- .../nodejs/havelessbemore/src/types/request.ts | 7 ++++++- .../nodejs/havelessbemore/src/utils/utf8Trie.ts | 6 +++--- 9 files changed, 33 insertions(+), 22 deletions(-) diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index 875863e..55b88be 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -1,3 +1,3 @@ -import{availableParallelism as V}from"node:os";import{fileURLToPath as K}from"node:url";import{isMainThread as G,parentPort as b}from"node:worker_threads";import{createWriteStream as x}from"node:fs";import{open as Z}from"node:fs/promises";import{stdout as v}from"node:process";function d(e,t,r){return e>t?e<=r?e:r:t}async function w(e,t,r,I=0){let u=(await e.stat()).size,f=Math.max(I,Math.floor(u/t)),p=Buffer.allocUnsafe(r),a=[],n=0;for(let o=f;o=0&&me.length&&(e=T(e,f+218)),e[0]+=218,e[u+0]=f,e[f+0]=e[1]),u=f}return[e,u]}function g(e=0,t=655360){t=Math.max(219,t);let r=new Int32Array(new SharedArrayBuffer(t<<2));return r[0]=219,r[1]=e,r}function T(e,t=0){let r=e[0];t=Math.max(t,Math.ceil(r*1.6180339887));let I=new Int32Array(new SharedArrayBuffer(t<<2));for(let u=0;ue[n].length&&(e[n]=T(e[n],s+2),u.add(n)),e[n][0]+=2,e[n][o+0]=s,e[n][s+0]=h,e[n][s+1]=M;else{let i=e[n][s+0];n!==i&&(s=e[n][s+1]),f.push([i,s,h,M])}}o+=1,m+=1}}f.splice(0,p)}while(f.length>0);return Array.from(u)}function U(e,t,r,I,u="",f){let p=new Array(t.length+1);p[0]=[r,3,0];let a=0,n=!1;do{let[o,c,m]=p[a];if(m>=216){--a;continue}p[a][1]+=1,++p[a][2];let l=e[o][c+0];if(l===0)continue;let R=e[o][l+0];o!==R&&(l=e[o][l+1],o=R),t[a]=m+32,p[++a]=[o,l+2,0];let M=e[o][l+1];M!==0&&(n&&I.write(u),n=!0,f(I,t,a,M))}while(a>=0)}import{Worker as W}from"node:worker_threads";function O(e){let t=new W(e);return t.on("error",r=>{throw r}),t.on("messageerror",r=>{throw r}),t.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${t.threadId} exited with code ${r}`)}),t}function y(e,t){return new Promise(r=>{e.once("message",r),e.postMessage(t)})}async function C(e,t,r,I=""){r=d(r,1,512);let u=await Z(e,"r"),f=await w(u,r,107,16384);r=f.length;let p=new SharedArrayBuffer(1e4*r+1<<4),a=new Int16Array(p),n=new Int16Array(p,2),o=new Uint32Array(p,4),c=new Float64Array(p,8),m=new Array(r),l=[],R=new Array(r);for(let i=0;i{let E=_.id;for(m[_.id]=_.trie;l.length>0;){let X=await y(D,{type:"merge",a:E,b:l.pop(),counts:o,maxes:n,mins:a,sums:c,tries:m});for(let A of X.ids)m[A]=X.tries[A]}return l.push(E),D.terminate()})}await Promise.all(R),await u.close();let M=x(I,{fd:I.length<1?v.fd:void 0,flags:"a",highWaterMark:1048576}),h=Buffer.allocUnsafe(100);M.write("{"),U(m,h,l[0],M,", ",s),M.end(`} -`);function s(i,D,_,E){let X=Math.round(c[E<<1]/o[E<<2]);i.write(D.toString("utf8",0,_)),i.write("="),i.write((a[E<<3]/10).toFixed(1)),i.write("/"),i.write((X/10).toFixed(1)),i.write("/"),i.write((n[E<<3]/10).toFixed(1))}}import{createReadStream as F}from"node:fs";var P=11*48,q=111*48;function H(e,t,r){return e[t]===45?(++t,t+4>r?P-10*e[t]-e[t+2]:q-100*e[t]-10*e[t+1]-e[t+3]):t+4>r?10*e[t]+e[t+2]-P:100*e[t]+10*e[t+1]+e[t+3]-q}async function k({end:e,fd:t,id:r,start:I,counts:u,maxes:f,mins:p,sums:a}){if(I>=e)return{id:r,trie:g(r,0)};let n=g(r),o=r*1e4+1,c=Buffer.allocUnsafe(107),m={autoClose:!1,fd:t,start:I,end:e-1,highWaterMark:L(e-I)},l=-1,R;for await(let s of F("",m)){let i=s.length;for(let D=0;D=i?f[s]:i,++u[s>>1],a[s>>2]+=i}return{id:r,trie:n}}function B({a:e,b:t,tries:r,counts:I,maxes:u,mins:f,sums:p}){function a(o,c){o<<=3,c<<=3,f[o]=Math.min(f[o],f[c]),u[o]=Math.max(u[o],u[c]),I[o>>1]+=I[c>>1],p[o>>2]+=p[c>>2]}return{ids:S(r,e,t,a),tries:r}}if(G){let e=K(import.meta.url);C(process.argv[2],e,V())}else b.addListener("message",async e=>{if(e.type==="process")b.postMessage(await k(e));else if(e.type==="merge")b.postMessage(B(e));else throw new Error("Unknown message type")}); +import{availableParallelism as V}from"node:os";import{fileURLToPath as G}from"node:url";import{isMainThread as K,parentPort as b}from"node:worker_threads";import{createWriteStream as x}from"node:fs";import{open as Z}from"node:fs/promises";import{stdout as v}from"node:process";function d(e,t,r){return e>t?e<=r?e:r:t}async function w(e,t,r,I=0){let u=(await e.stat()).size,f=Math.max(I,Math.floor(u/t)),c=Buffer.allocUnsafe(r),a=[],n=0;for(let o=f;o=0&&me.length&&(e=T(e,f+218)),e[0]+=218,e[u+0]=f,e[f+0]=e[1]),u=f}return[e,u]}function g(e=0,t=655360){t=Math.max(219,t);let r=new Int32Array(new SharedArrayBuffer(t<<2));return r[0]=219,r[1]=e,r}function T(e,t=0){let r=e[0];t=Math.max(t,Math.ceil(r*1.618033988749895));let I=new Int32Array(new SharedArrayBuffer(t<<2));for(let u=0;ue[n].length&&(e[n]=T(e[n],s+2),u.push(n)),e[n][0]+=2,e[n][o+0]=s,e[n][s+0]=h,e[n][s+1]=R;else{let i=e[n][s+0];n!==i&&(s=e[n][s+1]),f.push([i,s,h,R])}}o+=1,m+=1}}f.splice(0,c)}while(f.length>0);return u}function O(e,t,r,I,u="",f){let c=new Array(t.length+1);c[0]=[r,3,0];let a=0,n=!1;do{let[o,p,m]=c[a];if(m>=216){--a;continue}c[a][1]+=1,++c[a][2];let l=e[o][p+0];if(l===0)continue;let M=e[o][l+0];o!==M&&(l=e[o][l+1],o=M),t[a]=m+32,c[++a]=[o,l+2,0];let R=e[o][l+1];R!==0&&(n&&I.write(u),n=!0,f(I,t,a,R))}while(a>=0)}import{Worker as W}from"node:worker_threads";function C(e){let t=new W(e);return t.on("error",r=>{throw r}),t.on("messageerror",r=>{throw r}),t.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${t.threadId} exited with code ${r}`)}),t}function y(e,t){return new Promise(r=>{e.once("message",r),e.postMessage(t)})}async function U(e,t,r,I=""){r=d(r,1,512);let u=await Z(e,"r"),f=await w(u,r,107,16384);r=f.length;let c=new SharedArrayBuffer(1e4*r+1<<4),a=new Int16Array(c),n=new Int16Array(c,2),o=new Uint32Array(c,4),p=new Float64Array(c,8),m=new Array(r),l=[],M=new Array(r);for(let i=0;i{let E=_.id;for(m[_.id]=_.trie;l.length>0;){let X=await y(D,{type:1,a:E,b:l.pop(),counts:o,maxes:n,mins:a,sums:p,tries:m});for(let A of X.ids)m[A]=X.tries[A]}return l.push(E),D.terminate()})}await Promise.all(M),await u.close();let R=x(I,{fd:I.length<1?v.fd:void 0,flags:"a",highWaterMark:1048576}),h=Buffer.allocUnsafe(100);R.write("{"),O(m,h,l[0],R,", ",s),R.end(`} +`);function s(i,D,_,E){let X=Math.round(p[E<<1]/o[E<<2]);i.write(D.toString("utf8",0,_)),i.write("="),i.write((a[E<<3]/10).toFixed(1)),i.write("/"),i.write((X/10).toFixed(1)),i.write("/"),i.write((n[E<<3]/10).toFixed(1))}}import{createReadStream as F}from"node:fs";var P=11*48,q=111*48;function H(e,t,r){return e[t]===45?(++t,t+4>r?P-10*e[t]-e[t+2]:q-100*e[t]-10*e[t+1]-e[t+3]):t+4>r?10*e[t]+e[t+2]-P:100*e[t]+10*e[t+1]+e[t+3]-q}async function k({end:e,fd:t,id:r,start:I,counts:u,maxes:f,mins:c,sums:a}){if(I>=e)return{id:r,trie:g(r,0)};let n=g(r),o=r*1e4+1,p=Buffer.allocUnsafe(107),m={autoClose:!1,fd:t,start:I,end:e-1,highWaterMark:L(e-I)},l=-1,M;for await(let s of F("",m)){let i=s.length;for(let D=0;D=i?f[s]:i,++u[s>>1],a[s>>2]+=i}return{id:r,trie:n}}function B({a:e,b:t,tries:r,counts:I,maxes:u,mins:f,sums:c}){function a(o,p){o<<=3,p<<=3,f[o]=Math.min(f[o],f[p]),u[o]=Math.max(u[o],u[p]),I[o>>1]+=I[p>>1],c[o>>2]+=c[p>>2]}return{ids:S(r,e,t,a),tries:r}}if(K){let e=G(import.meta.url);U(process.argv[2],e,V())}else b.addListener("message",async e=>{if(e.type===0)b.postMessage(await k(e));else if(e.type===1)b.postMessage(B(e));else throw new Error("Unknown message type")}); //# sourceMappingURL=index.mjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index cfe26a2..e9b1c21 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../src/index.ts", "../src/main.ts", "../src/utils/stream.ts", "../src/utils/utf8Trie.ts", "../src/utils/worker.ts", "../src/worker.ts", "../src/utils/parse.ts"], - "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === \"process\") {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === \"merge\") {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { WriteStream, createWriteStream } from \"node:fs\";\nimport { open } from \"node:fs/promises\";\nimport { stdout } from \"node:process\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Open the given file\n const file = await open(filePath, \"r\");\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n file,\n maxWorkers,\n BRC.MAX_ENTRY_LEN,\n Config.CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: \"process\",\n counts,\n end: chunks[i][1],\n fd: file.fd,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[res.id] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: \"merge\",\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Close the file\n await file.close();\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? stdout.fd : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { FileHandle } from \"fs/promises\";\n\nimport { Config } from \"../constants/config\";\nimport { CharCode } from \"../constants/utf8\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n file: FileHandle,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CharCode.NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= Config.HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, Config.HIGH_WATER_MARK_MIN, Config.HIGH_WATER_MARK_MAX);\n}\n", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown = new Set();\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.add(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return Array.from(grown);\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"node:worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { createReadStream } from \"node:fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n fd,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * BRC.MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(BRC.MAX_ENTRY_LEN);\n\n // Create readstream options\n const opts = {\n autoClose: false,\n fd,\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n };\n\n // For each chunk\n let bufI = -1;\n let leaf: number;\n for await (const chunk of createReadStream(\"\", opts)) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // Add byte to buffer\n buffer[++bufI] = chunk[i];\n\n // If newline\n if (chunk[i] === CharCode.NEWLINE) {\n // Get semicolon\n let semI = bufI - 5;\n if (buffer[semI] !== CharCode.SEMICOLON) {\n semI += 1 | (1 + ~(buffer[semI - 1] === CharCode.SEMICOLON));\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = -1;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TrieNodeProto.VALUE_IDX] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf + TrieNodeProto.VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TrieNodeProto.VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], - "mappings": "AAAA,OAAS,wBAAAA,MAA4B,UACrC,OAAS,iBAAAC,MAAqB,WAC9B,OAAS,gBAAAC,EAAc,cAAAC,MAAkB,sBCFzC,OAAsB,qBAAAC,MAAyB,UAC/C,OAAS,QAAAC,MAAY,mBACrB,OAAS,UAAAC,MAAc,eCYhB,SAASC,EAAMC,EAAeC,EAAaC,EAAqB,CACrE,OAAOF,EAAQC,EAAOD,GAASE,EAAMF,EAAQE,EAAOD,CACtD,CAoBA,eAAsBE,EACpBC,EACAC,EACAC,EACAC,EAAU,EACmB,CAE7B,IAAMC,GAAQ,MAAMJ,EAAK,KAAK,GAAG,KAE3BK,EAAY,KAAK,IAAIF,EAAS,KAAK,MAAMC,EAAOH,CAAM,CAAC,EAEvDK,EAAS,OAAO,YAAYJ,CAAa,EACzCK,EAA6B,CAAC,EAEhCC,EAAQ,EACZ,QAASC,EAAMJ,EAAWI,EAAML,EAAMK,GAAOJ,EAAW,CAEtD,IAAMK,EAAM,MAAMV,EAAK,KAAKM,EAAQ,EAAGJ,EAAeO,CAAG,EAEnDE,EAAUL,EAAO,UAAwB,EAE3CK,GAAW,GAAKA,EAAUD,EAAI,YAEhCD,GAAOE,EAAU,EAEjBJ,EAAO,KAAK,CAACC,EAAOC,CAAG,CAAC,EAExBD,EAAQC,EAEZ,CAEA,OAAID,EAAQJ,GACVG,EAAO,KAAK,CAACC,EAAOJ,CAAI,CAAC,EAGpBG,CACT,CASO,SAASK,EAAiBR,EAAsB,CAErD,OAAAA,GAAQ,OAERA,EAAO,KAAK,MAAM,KAAK,KAAKA,CAAI,CAAC,EAEjCA,EAAO,GAAKA,EAELT,EAAMS,eAA4D,CAC3E,CC/EO,SAASS,EACdC,EACAC,EACAC,EACAC,EACsB,CACtB,IAAIC,IACJ,KAAOF,EAAMC,GAAK,CAChBC,GACE,EACA,GAAwBH,EAAIC,GAAK,EAAI,IACvC,IAAIG,EAAQL,EAAKI,EAAQ,CAAwB,EAC7CC,IAAU,IAEZA,EAAQL,GAAuB,EAC3BK,EAAQ,IAAoBL,EAAK,SACnCA,EAAOM,EAAKN,EAAMK,EAAQ,GAAiB,GAE7CL,GAAuB,GAAK,IAE5BA,EAAKI,EAAQ,CAAwB,EAAIC,EAEzCL,EAAKK,EAAQ,CAAoB,EAAIL,GAAqB,GAE5DI,EAAQC,CACV,CAEA,MAAO,CAACL,EAAMI,CAAK,CACrB,CA8BO,SAASG,EAAWC,EAAK,EAAGC,SAAsC,CACvEA,EAAO,KAAK,QAAmBA,CAAI,EACnC,IAAMC,EAAO,IAAI,WAAW,IAAI,kBAAkBD,GAAQ,CAAC,CAAC,EAC5D,OAAAC,GAAuB,EAAI,IAC3BA,GAAqB,EAAIF,EAClBE,CACT,CAEO,SAASC,EAAKD,EAAkBE,EAAU,EAAe,CAC9D,IAAMC,EAASH,GAAuB,EACtCE,EAAU,KAAK,IAAIA,EAAS,KAAK,KAAKC,EAAS,YAAkB,CAAC,EAClE,IAAMC,EAAO,IAAI,WAAW,IAAI,kBAAkBF,GAAW,CAAC,CAAC,EAC/D,QAASG,EAAI,EAAGA,EAAIF,EAAQ,EAAEE,EAC5BD,EAAKC,CAAC,EAAIL,EAAKK,CAAC,EAElB,OAAOD,CACT,CAEO,SAASE,EACdC,EACAC,EACAC,EACAC,EACU,CACV,IAAMC,EAAQ,IAAI,IACZC,EAA4C,CAChD,CAACJ,IAAwBC,GAAsB,CACjD,EAEA,EAAG,CACD,IAAMI,EAAID,EAAM,OAChB,QAASE,EAAI,EAAGA,EAAID,EAAG,EAAEC,EAAG,CAE1B,GAAI,CAACN,EAAIO,EAAIN,EAAIO,CAAE,EAAIJ,EAAME,CAAC,EAGxBG,EAAMV,EAAME,CAAE,EAAEO,EAAK,CAAuB,EAClD,GAAIC,IAAQ,EAAW,CAErB,IAAMC,EAAMX,EAAMC,CAAE,EAAEO,EAAK,CAAuB,EAC9CG,IAAQ,EACVR,EAAQQ,EAAKD,CAAG,EAEhBV,EAAMC,CAAE,EAAEO,EAAK,CAAuB,EAAIE,CAE9C,CAGAF,GAAM,EACNC,GAAM,EAGN,IAAMG,EAAKH,EAAK,IAChB,KAAOA,EAAKG,GAAI,CAEd,IAAIC,EAAKb,EAAME,CAAE,EAAEO,EAAK,CAAwB,EAChD,GAAII,IAAO,EAAW,CAEpB,IAAMC,EAAKd,EAAME,CAAE,EAAEW,EAAK,CAAoB,EAC1CX,IAAOY,IACTD,EAAKb,EAAME,CAAE,EAAEW,EAAK,CAAyB,GAI/C,IAAIE,EAAKf,EAAMC,CAAE,EAAEO,EAAK,CAAwB,EAChD,GAAIO,IAAO,EAETA,EAAKf,EAAMC,CAAE,GAAoB,EAC7Bc,EAAK,EAAwBf,EAAMC,CAAE,EAAE,SACzCD,EAAMC,CAAE,EAAIP,EAAKM,EAAMC,CAAE,EAAGc,EAAK,CAAqB,EACtDX,EAAM,IAAIH,CAAE,GAEdD,EAAMC,CAAE,GAAoB,GAAK,EAEjCD,EAAMC,CAAE,EAAEO,EAAK,CAAwB,EAAIO,EAE3Cf,EAAMC,CAAE,EAAEc,EAAK,CAAwB,EAAID,EAC3Cd,EAAMC,CAAE,EAAEc,EAAK,CAAyB,EAAIF,MACvC,CAEL,IAAMG,EAAKhB,EAAMC,CAAE,EAAEc,EAAK,CAAoB,EAC1Cd,IAAOe,IACTD,EAAKf,EAAMC,CAAE,EAAEc,EAAK,CAAyB,GAG/CV,EAAM,KAAK,CAACW,EAAID,EAAID,EAAID,CAAE,CAAC,CAC7B,CACF,CAGAL,GAAM,EACNC,GAAM,CACR,CACF,CACAJ,EAAM,OAAO,EAAGC,CAAC,CACnB,OAASD,EAAM,OAAS,GACxB,OAAO,MAAM,KAAKD,CAAK,CACzB,CAEO,SAASa,EACdjB,EACAkB,EACAC,EACAC,EACAC,EAAY,GACZC,EAMM,CACN,IAAMC,EAAQ,IAAI,MAAgCL,EAAI,OAAS,CAAC,EAChEK,EAAM,CAAC,EAAI,CAACJ,EAAW,EAAiD,CAAC,EAEzE,IAAIK,EAAM,EACNC,EAAO,GACX,EAAG,CAED,GAAI,CAACC,EAAOC,EAAUC,CAAQ,EAAIL,EAAMC,CAAG,EAG3C,GAAII,GAAY,IAA4B,CAC1C,EAAEJ,EACF,QACF,CAGAD,EAAMC,CAAG,EAAE,CAAC,GAAK,EACjB,EAAED,EAAMC,CAAG,EAAE,CAAC,EAGd,IAAIK,EAAS7B,EAAM0B,CAAK,EAAEC,EAAW,CAAwB,EAC7D,GAAIE,IAAW,EACb,SAIF,IAAMC,EAAa9B,EAAM0B,CAAK,EAAEG,EAAS,CAAoB,EACzDH,IAAUI,IACZD,EAAS7B,EAAM0B,CAAK,EAAEG,EAAS,CAAyB,EACxDH,EAAQI,GAIVZ,EAAIM,CAAG,EAAII,EAAW,GACtBL,EAAM,EAAEC,CAAG,EAAI,CAACE,EAAOG,EAAS,EAA4B,CAAC,EAG7D,IAAME,EAAa/B,EAAM0B,CAAK,EAAEG,EAAS,CAAuB,EAC5DE,IAAe,IAEbN,GACFL,EAAO,MAAMC,CAAS,EAExBI,EAAO,GACPH,EAAWF,EAAQF,EAAKM,EAAKO,CAAU,EAE3C,OAASP,GAAO,EAClB,CCpOA,OAAS,UAAAQ,MAAc,sBAShB,SAASC,EAAaC,EAA4B,CACvD,IAAMC,EAAS,IAAIH,EAAOE,CAAU,EACpC,OAAAC,EAAO,GAAG,QAAUC,GAAQ,CAC1B,MAAMA,CACR,CAAC,EACDD,EAAO,GAAG,eAAiBC,GAAQ,CACjC,MAAMA,CACR,CAAC,EACDD,EAAO,GAAG,OAASE,GAAS,CAC1B,GAAIA,EAAO,GAAKA,EAAO,EACrB,MAAM,IAAI,MAAM,UAAUF,EAAO,QAAQ,qBAAqBE,CAAI,EAAE,CAExE,CAAC,EACMF,CACT,CAUO,SAASG,EAAeH,EAAgBI,EAAwB,CACrE,OAAO,IAAI,QAAcC,GAAY,CACnCL,EAAO,KAAK,UAAWK,CAAO,EAC9BL,EAAO,YAAYI,CAAG,CACxB,CAAC,CACH,CHvBA,eAAsBE,EACpBC,EACAC,EACAC,EACAC,EAAU,GACK,CAEfD,EAAaE,EAAMF,OAAkD,EAGrE,IAAMG,EAAO,MAAMC,EAAKN,EAAU,GAAG,EAG/BO,EAAS,MAAMC,EACnBH,EACAH,WAGF,EAGAA,EAAaK,EAAO,OAGpB,IAAME,EAAS,IAAI,kBAChB,IAAmBP,EAAa,GAAM,CACzC,EACMQ,EAAO,IAAI,WAAWD,CAAM,EAC5BE,EAAQ,IAAI,WAAWF,EAAQ,CAAC,EAChCG,EAAS,IAAI,YAAYH,EAAQ,CAAC,EAClCI,EAAO,IAAI,aAAaJ,EAAQ,CAAC,EACjCK,EAAQ,IAAI,MAAkBZ,CAAU,EAGxCa,EAAqB,CAAC,EACtBC,EAAQ,IAAI,MAAwBd,CAAU,EACpD,QAAS,EAAI,EAAG,EAAIA,EAAY,EAAE,EAAG,CAEnC,IAAMe,EAASC,EAAajB,CAAU,EAEtCe,EAAM,CAAC,EAAIG,EAAsCF,EAAQ,CACvD,KAAM,UACN,OAAAL,EACA,IAAKL,EAAO,CAAC,EAAE,CAAC,EAChB,GAAIF,EAAK,GACT,GAAI,EACJ,MAAAM,EACA,KAAAD,EACA,MAAOH,EAAO,CAAC,EAAE,CAAC,EAClB,KAAAM,CACF,CAAC,EAAE,KAAK,MAAOO,GAAQ,CAErB,IAAMC,EAAID,EAAI,GAGd,IAFAN,EAAMM,EAAI,EAAE,EAAIA,EAAI,KAEbL,EAAS,OAAS,GAAG,CAC1B,IAAMK,EAAM,MAAMD,EAAkCF,EAAQ,CAC1D,KAAM,QACN,EAAAI,EACA,EAAGN,EAAS,IAAI,EAChB,OAAAH,EACA,MAAAD,EACA,KAAAD,EACA,KAAAG,EACA,MAAAC,CACF,CAAC,EAED,QAAWQ,KAAMF,EAAI,IACnBN,EAAMQ,CAAE,EAAIF,EAAI,MAAME,CAAE,CAE5B,CACA,OAAAP,EAAS,KAAKM,CAAC,EAERJ,EAAO,UAAU,CAC1B,CAAC,CACH,CAGA,MAAM,QAAQ,IAAID,CAAK,EAGvB,MAAMX,EAAK,MAAM,EAGjB,IAAMkB,EAAMC,EAAkBrB,EAAS,CACrC,GAAIA,EAAQ,OAAS,EAAIsB,EAAO,GAAK,OACrC,MAAO,IACP,qBACF,CAAC,EACKC,EAAS,OAAO,eAAoC,EAC1DH,EAAI,MAAM,GAAG,EACbI,EAAMb,EAAOY,EAAQX,EAAS,CAAC,EAAGQ,EAAK,KAAMK,CAAY,EACzDL,EAAI,IAAI;AAAA,CAAK,EAEb,SAASK,EACPC,EACAC,EACAC,EACAC,EACM,CACN,IAAMC,EAAM,KAAK,MAAMpB,EAAKmB,GAAM,CAAC,EAAIpB,EAAOoB,GAAM,CAAC,CAAC,EACtDH,EAAO,MAAMC,EAAK,SAAS,OAAQ,EAAGC,CAAO,CAAC,EAC9CF,EAAO,MAAM,GAAG,EAChBA,EAAO,OAAOnB,EAAKsB,GAAM,CAAC,EAAI,IAAI,QAAQ,CAAC,CAAC,EAC5CH,EAAO,MAAM,GAAG,EAChBA,EAAO,OAAOI,EAAM,IAAI,QAAQ,CAAC,CAAC,EAClCJ,EAAO,MAAM,GAAG,EAChBA,EAAO,OAAOlB,EAAMqB,GAAM,CAAC,EAAI,IAAI,QAAQ,CAAC,CAAC,CAC/C,CACF,CI5HA,OAAS,oBAAAE,MAAwB,UCE1B,IAAMC,EAAe,GAAK,GACpBC,EAAgB,IAAM,GAO5B,SAASC,EAAYC,EAAWC,EAAaC,EAAqB,CACvE,OAAIF,EAAEC,CAAG,IAAM,IACb,EAAEA,EACKA,EAAM,EAAIC,EACbL,EAAe,GAAKG,EAAEC,CAAG,EAAID,EAAEC,EAAM,CAAC,EACtCH,EAAgB,IAAME,EAAEC,CAAG,EAAI,GAAKD,EAAEC,EAAM,CAAC,EAAID,EAAEC,EAAM,CAAC,GAEzDA,EAAM,EAAIC,EACb,GAAKF,EAAEC,CAAG,EAAID,EAAEC,EAAM,CAAC,EAAIJ,EAC3B,IAAMG,EAAEC,CAAG,EAAI,GAAKD,EAAEC,EAAM,CAAC,EAAID,EAAEC,EAAM,CAAC,EAAIH,CACpD,CDPA,eAAsBK,EAAI,CACxB,IAAAC,EACA,GAAAC,EACA,GAAAC,EACA,MAAAC,EAEA,OAAAC,EACA,MAAAC,EACA,KAAAC,EACA,KAAAC,CACF,EAA6C,CAE3C,GAAIJ,GAASH,EACX,MAAO,CAAE,GAAAE,EAAI,KAAMM,EAAWN,EAAI,CAAC,CAAE,EAIvC,IAAIO,EAAOD,EAAWN,CAAE,EACpBQ,EAAWR,EAAK,IAAmB,EACjCS,EAAS,OAAO,eAA6B,EAG7CC,EAAO,CACX,UAAW,GACX,GAAAX,EACA,MAAAE,EACA,IAAKH,EAAM,EACX,cAAea,EAAiBb,EAAMG,CAAK,CAC7C,EAGIW,EAAO,GACPC,EACJ,cAAiBC,KAASC,EAAiB,GAAIL,CAAI,EAAG,CAEpD,IAAMM,EAAIF,EAAM,OAChB,QAASG,EAAI,EAAGA,EAAID,EAAG,EAAEC,EAKvB,GAHAR,EAAO,EAAEG,CAAI,EAAIE,EAAMG,CAAC,EAGpBH,EAAMG,CAAC,IAAM,GAAkB,CAEjC,IAAIC,EAAON,EAAO,EACdH,EAAOS,CAAI,IAAM,KACnBA,GAAQ,EAAK,EAAI,EAAET,EAAOS,EAAO,CAAC,IAAM,KAI1C,IAAMC,EAAQC,EAAYX,EAAQS,EAAO,EAAGN,CAAI,EAChDA,EAAO,GAGP,CAACL,EAAMM,CAAI,EAAIQ,EAAId,EAAME,EAAQ,EAAGS,CAAI,EAGpCX,EAAKM,EAAO,CAAuB,IAAM,EAE3CS,EAAcf,EAAKM,EAAO,CAAuB,EAAGM,CAAK,GAGzDZ,EAAKM,EAAO,CAAuB,EAAIL,EACvCe,EAAWf,IAAYW,CAAK,EAEhC,CAEJ,CAEA,SAASI,EAAWC,EAAeC,EAAoB,CACrDrB,EAAKoB,GAAS,CAAC,EAAIC,EACnBtB,EAAMqB,GAAS,CAAC,EAAIC,EACpBvB,EAAOsB,GAAS,CAAC,EAAI,EACrBnB,EAAKmB,GAAS,CAAC,EAAIC,CACrB,CAEA,SAASH,EAAcE,EAAeC,EAAoB,CACxDD,IAAU,EACVpB,EAAKoB,CAAK,EAAIpB,EAAKoB,CAAK,GAAKC,EAAOrB,EAAKoB,CAAK,EAAIC,EAClDtB,EAAMqB,CAAK,EAAIrB,EAAMqB,CAAK,GAAKC,EAAOtB,EAAMqB,CAAK,EAAIC,EACrD,EAAEvB,EAAOsB,GAAS,CAAC,EACnBnB,EAAKmB,GAAS,CAAC,GAAKC,CACtB,CAEA,MAAO,CAAE,GAAAzB,EAAI,KAAAO,CAAK,CACpB,CAEO,SAASmB,EAAM,CACpB,EAAAC,EACA,EAAAC,EACA,MAAAC,EACA,OAAA3B,EACA,MAAAC,EACA,KAAAC,EACA,KAAAC,CACF,EAAgC,CAC9B,SAASyB,EAAcC,EAAYC,EAAkB,CACnDD,IAAO,EACPC,IAAO,EACP5B,EAAK2B,CAAE,EAAI,KAAK,IAAI3B,EAAK2B,CAAE,EAAG3B,EAAK4B,CAAE,CAAC,EACtC7B,EAAM4B,CAAE,EAAI,KAAK,IAAI5B,EAAM4B,CAAE,EAAG5B,EAAM6B,CAAE,CAAC,EACzC9B,EAAO6B,GAAM,CAAC,GAAK7B,EAAO8B,GAAM,CAAC,EACjC3B,EAAK0B,GAAM,CAAC,GAAK1B,EAAK2B,GAAM,CAAC,CAC/B,CAEA,MAAO,CAAE,IADGC,EAAUJ,EAAOF,EAAGC,EAAGE,CAAa,EAClC,MAAAD,CAAM,CACtB,CL3GA,GAAIK,EAAc,CAChB,IAAMC,EAAaC,EAAc,YAAY,GAAG,EAChDC,EAAQ,QAAQ,KAAK,CAAC,EAAGF,EAAYG,EAAqB,CAAC,CAC7D,MACEC,EAAY,YAAY,UAAW,MAAOC,GAAiB,CACzD,GAAIA,EAAI,OAAS,UACfD,EAAY,YAAY,MAAMF,EAAUG,CAAqB,CAAC,UACrDA,EAAI,OAAS,QACtBD,EAAY,YAAYE,EAAMD,CAAmB,CAAC,MAElD,OAAM,IAAI,MAAM,sBAAsB,CAE1C,CAAC", + "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport { RequestType, type Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === RequestType.PROCESS) {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === RequestType.MERGE) {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { WriteStream, createWriteStream } from \"node:fs\";\nimport { open } from \"node:fs/promises\";\nimport { stdout } from \"node:process\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\nimport { RequestType } from \"./types/request\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Open the given file\n const file = await open(filePath, \"r\");\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n file,\n maxWorkers,\n BRC.MAX_ENTRY_LEN,\n Config.CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: RequestType.PROCESS,\n counts,\n end: chunks[i][1],\n fd: file.fd,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[res.id] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: RequestType.MERGE,\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Close the file\n await file.close();\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? stdout.fd : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { FileHandle } from \"fs/promises\";\n\nimport { Config } from \"../constants/config\";\nimport { CharCode } from \"../constants/utf8\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n file: FileHandle,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CharCode.NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= Config.HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, Config.HIGH_WATER_MARK_MIN, Config.HIGH_WATER_MARK_MAX);\n}\n", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown: number[] = [];\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.push(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return grown;\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"node:worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { createReadStream } from \"node:fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n fd,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * BRC.MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(BRC.MAX_ENTRY_LEN);\n\n // Create readstream options\n const opts = {\n autoClose: false,\n fd,\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n };\n\n // For each chunk\n let bufI = -1;\n let leaf: number;\n for await (const chunk of createReadStream(\"\", opts)) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // Add byte to buffer\n buffer[++bufI] = chunk[i];\n\n // If newline\n if (chunk[i] === CharCode.NEWLINE) {\n // Get semicolon\n let semI = bufI - 5;\n if (buffer[semI] !== CharCode.SEMICOLON) {\n semI += 1 | (1 + ~(buffer[semI - 1] === CharCode.SEMICOLON));\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = -1;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TrieNodeProto.VALUE_IDX] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf + TrieNodeProto.VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TrieNodeProto.VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], + "mappings": "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", "names": ["availableParallelism", "fileURLToPath", "isMainThread", "parentPort", "createWriteStream", "open", "stdout", "clamp", "value", "min", "max", "getFileChunks", "file", "target", "maxLineLength", "minSize", "size", "chunkSize", "buffer", "chunks", "start", "end", "res", "newline", "getHighWaterMark", "add", "trie", "key", "min", "max", "index", "child", "grow", "createTrie", "id", "size", "trie", "grow", "minSize", "length", "next", "i", "mergeLeft", "tries", "at", "bt", "mergeFn", "grown", "queue", "Q", "q", "ai", "bi", "bvi", "avi", "bn", "ri", "rt", "li", "lt", "print", "key", "trieIndex", "stream", "separator", "callbackFn", "stack", "top", "tail", "trieI", "childPtr", "numChild", "childI", "childTrieI", "valueIndex", "Worker", "createWorker", "workerPath", "worker", "err", "code", "exec", "req", "resolve", "run", "filePath", "workerPath", "maxWorkers", "outPath", "clamp", "file", "open", "chunks", "getFileChunks", "valBuf", "mins", "maxes", "counts", "sums", "tries", "unmerged", "tasks", "worker", "createWorker", "exec", "res", "a", "id", "out", "createWriteStream", "stdout", "buffer", "print", "printStation", "stream", "name", "nameLen", "vi", "avg", "createReadStream", "CHAR_ZERO_11", "CHAR_ZERO_111", "parseDouble", "b", "min", "max", "run", "end", "fd", "id", "start", "counts", "maxes", "mins", "sums", "createTrie", "trie", "stations", "buffer", "opts", "getHighWaterMark", "bufI", "leaf", "chunk", "createReadStream", "N", "i", "semI", "tempV", "parseDouble", "add", "updateStation", "newStation", "index", "temp", "merge", "a", "b", "tries", "mergeStations", "ai", "bi", "mergeLeft", "isMainThread", "workerPath", "fileURLToPath", "run", "availableParallelism", "parentPort", "msg", "merge"] } diff --git a/src/main/nodejs/havelessbemore/src/constants/utf8.ts b/src/main/nodejs/havelessbemore/src/constants/utf8.ts index 65c2cb2..6fa19ad 100644 --- a/src/main/nodejs/havelessbemore/src/constants/utf8.ts +++ b/src/main/nodejs/havelessbemore/src/constants/utf8.ts @@ -69,24 +69,29 @@ export const enum UTF8 { B0_2B_MAX = 0b11011111, B0_3B_MAX = 0b11101111, B0_4B_MAX = 0b11110111, - */ + */ } export const enum Trie { /** - * Represents a `null` trie element. + * The size in bytes of each element in the trie. */ - NULL = 0, + BYTES_PER_ELEMENT = 4, // Int32Array.BYTES_PER_ELEMENT, /** - * The default initial size of a trie. + * The default / initial size of a trie. */ DEFAULT_SIZE = 655360, // 2.5 MiB /** * The growth factor for resizing a trie. */ - GROWTH_FACTOR = 1.6180339887, + GROWTH_FACTOR = 1.618033988749895, // Phi; (1 + sqrt(5)) / 2 + + /** + * Represents a `null` trie element. + */ + NULL = 0, } /** diff --git a/src/main/nodejs/havelessbemore/src/index.ts b/src/main/nodejs/havelessbemore/src/index.ts index 3d6c0d3..1dadc67 100644 --- a/src/main/nodejs/havelessbemore/src/index.ts +++ b/src/main/nodejs/havelessbemore/src/index.ts @@ -4,7 +4,7 @@ import { isMainThread, parentPort } from "node:worker_threads"; import type { MergeRequest } from "./types/mergeRequest"; import type { ProcessRequest } from "./types/processRequest"; -import type { Request } from "./types/request"; +import { RequestType, type Request } from "./types/request"; import { run as runMain } from "./main"; import { merge, run as runWorker } from "./worker"; @@ -14,9 +14,9 @@ if (isMainThread) { runMain(process.argv[2], workerPath, availableParallelism()); } else { parentPort!.addListener("message", async (msg: Request) => { - if (msg.type === "process") { + if (msg.type === RequestType.PROCESS) { parentPort!.postMessage(await runWorker(msg as ProcessRequest)); - } else if (msg.type === "merge") { + } else if (msg.type === RequestType.MERGE) { parentPort!.postMessage(merge(msg as MergeRequest)); } else { throw new Error("Unknown message type"); diff --git a/src/main/nodejs/havelessbemore/src/main.ts b/src/main/nodejs/havelessbemore/src/main.ts index bd01d82..014135a 100644 --- a/src/main/nodejs/havelessbemore/src/main.ts +++ b/src/main/nodejs/havelessbemore/src/main.ts @@ -12,6 +12,7 @@ import { Config } from "./constants/config"; import { clamp, getFileChunks } from "./utils/stream"; import { print } from "./utils/utf8Trie"; import { createWorker, exec } from "./utils/worker"; +import { RequestType } from "./types/request"; export async function run( filePath: string, @@ -54,7 +55,7 @@ export async function run( const worker = createWorker(workerPath); // Process the chunk tasks[i] = exec(worker, { - type: "process", + type: RequestType.PROCESS, counts, end: chunks[i][1], fd: file.fd, @@ -70,7 +71,7 @@ export async function run( // Merge with other tries while (unmerged.length > 0) { const res = await exec(worker, { - type: "merge", + type: RequestType.MERGE, a, b: unmerged.pop()!, counts, diff --git a/src/main/nodejs/havelessbemore/src/types/mergeRequest.ts b/src/main/nodejs/havelessbemore/src/types/mergeRequest.ts index b58428a..0e8faaf 100644 --- a/src/main/nodejs/havelessbemore/src/types/mergeRequest.ts +++ b/src/main/nodejs/havelessbemore/src/types/mergeRequest.ts @@ -1,7 +1,7 @@ -import { Request } from "./request"; +import { Request, RequestType } from "./request"; export interface MergeRequest extends Request { - type: "merge"; + type: RequestType.MERGE; a: number; b: number; // Shared memory diff --git a/src/main/nodejs/havelessbemore/src/types/processRequest.ts b/src/main/nodejs/havelessbemore/src/types/processRequest.ts index a4e09bf..7936108 100644 --- a/src/main/nodejs/havelessbemore/src/types/processRequest.ts +++ b/src/main/nodejs/havelessbemore/src/types/processRequest.ts @@ -1,7 +1,7 @@ -import { Request } from "./request"; +import { Request, RequestType } from "./request"; export interface ProcessRequest extends Request { - type: "process"; + type: RequestType.PROCESS; end: number; fd: number; id: number; diff --git a/src/main/nodejs/havelessbemore/src/types/request.ts b/src/main/nodejs/havelessbemore/src/types/request.ts index 021468f..1f2ef50 100644 --- a/src/main/nodejs/havelessbemore/src/types/request.ts +++ b/src/main/nodejs/havelessbemore/src/types/request.ts @@ -1,3 +1,8 @@ +export const enum RequestType { + PROCESS, + MERGE, +} + export interface Request { - type: string; + type: RequestType; } diff --git a/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts b/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts index fdea362..06770bc 100644 --- a/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts +++ b/src/main/nodejs/havelessbemore/src/utils/utf8Trie.ts @@ -91,7 +91,7 @@ export function mergeLeft( bt: number, mergeFn: (ai: number, bi: number) => void, ): number[] { - const grown = new Set(); + const grown: number[] = []; const queue: [number, number, number, number][] = [ [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX], ]; @@ -137,7 +137,7 @@ export function mergeLeft( li = tries[at][TrieProto.SIZE_IDX]; if (li + TrieRedirectProto.MEM > tries[at].length) { tries[at] = grow(tries[at], li + TrieRedirectProto.MEM); - grown.add(at); + grown.push(at); } tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM; // Attach redirect @@ -163,7 +163,7 @@ export function mergeLeft( } queue.splice(0, Q); } while (queue.length > 0); - return Array.from(grown); + return grown; } export function print( From 4ed9b06ba0eea0e7328570013f8202a70efcf11a Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Sun, 26 May 2024 17:32:01 -0400 Subject: [PATCH 53/69] Update highWaterMark constants --- src/main/nodejs/havelessbemore/src/constants/config.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/nodejs/havelessbemore/src/constants/config.ts b/src/main/nodejs/havelessbemore/src/constants/config.ts index 0f0b4b1..7cea1e6 100644 --- a/src/main/nodejs/havelessbemore/src/constants/config.ts +++ b/src/main/nodejs/havelessbemore/src/constants/config.ts @@ -4,23 +4,23 @@ export const enum Config { /** * The minimum value in bytes for `highWaterMark`. */ - HIGH_WATER_MARK_MIN = 16384, // 16KiB + HIGH_WATER_MARK_MIN = 16384, // 16 KiB /** * The maximum value in bytes for `highWaterMark`. */ - HIGH_WATER_MARK_MAX = 1048576, // 1MiB + HIGH_WATER_MARK_MAX = 8388608, // 8 MiB /** * The `highWaterMark` for write streams. */ - HIGH_WATER_MARK_OUT = 1048576, // 1MiB + HIGH_WATER_MARK_OUT = 1048576, // 1 MiB /** * The ratio of the file size to use for calculating * the `highWaterMark` of a stream. */ - HIGH_WATER_MARK_RATIO = 0.000152, + HIGH_WATER_MARK_RATIO = 0.00625, /** * The minimum size in bytes of a file chunk. From 847f2b06d4b714d9b43eab3795fb7b99eea43aa1 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Sun, 26 May 2024 17:34:23 -0400 Subject: [PATCH 54/69] Replace createReadStream with manual streaming. This allows for better buffer usage / reuse --- src/main/nodejs/havelessbemore/dist/index.mjs | 4 +- .../nodejs/havelessbemore/dist/index.mjs.map | 6 +-- src/main/nodejs/havelessbemore/src/main.ts | 2 +- .../src/types/processRequest.ts | 2 +- src/main/nodejs/havelessbemore/src/worker.ts | 46 +++++++++---------- 5 files changed, 29 insertions(+), 31 deletions(-) diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index 55b88be..42d5460 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -1,3 +1,3 @@ -import{availableParallelism as V}from"node:os";import{fileURLToPath as G}from"node:url";import{isMainThread as K,parentPort as b}from"node:worker_threads";import{createWriteStream as x}from"node:fs";import{open as Z}from"node:fs/promises";import{stdout as v}from"node:process";function d(e,t,r){return e>t?e<=r?e:r:t}async function w(e,t,r,I=0){let u=(await e.stat()).size,f=Math.max(I,Math.floor(u/t)),c=Buffer.allocUnsafe(r),a=[],n=0;for(let o=f;o=0&&me.length&&(e=T(e,f+218)),e[0]+=218,e[u+0]=f,e[f+0]=e[1]),u=f}return[e,u]}function g(e=0,t=655360){t=Math.max(219,t);let r=new Int32Array(new SharedArrayBuffer(t<<2));return r[0]=219,r[1]=e,r}function T(e,t=0){let r=e[0];t=Math.max(t,Math.ceil(r*1.618033988749895));let I=new Int32Array(new SharedArrayBuffer(t<<2));for(let u=0;ue[n].length&&(e[n]=T(e[n],s+2),u.push(n)),e[n][0]+=2,e[n][o+0]=s,e[n][s+0]=h,e[n][s+1]=R;else{let i=e[n][s+0];n!==i&&(s=e[n][s+1]),f.push([i,s,h,R])}}o+=1,m+=1}}f.splice(0,c)}while(f.length>0);return u}function O(e,t,r,I,u="",f){let c=new Array(t.length+1);c[0]=[r,3,0];let a=0,n=!1;do{let[o,p,m]=c[a];if(m>=216){--a;continue}c[a][1]+=1,++c[a][2];let l=e[o][p+0];if(l===0)continue;let M=e[o][l+0];o!==M&&(l=e[o][l+1],o=M),t[a]=m+32,c[++a]=[o,l+2,0];let R=e[o][l+1];R!==0&&(n&&I.write(u),n=!0,f(I,t,a,R))}while(a>=0)}import{Worker as W}from"node:worker_threads";function C(e){let t=new W(e);return t.on("error",r=>{throw r}),t.on("messageerror",r=>{throw r}),t.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${t.threadId} exited with code ${r}`)}),t}function y(e,t){return new Promise(r=>{e.once("message",r),e.postMessage(t)})}async function U(e,t,r,I=""){r=d(r,1,512);let u=await Z(e,"r"),f=await w(u,r,107,16384);r=f.length;let c=new SharedArrayBuffer(1e4*r+1<<4),a=new Int16Array(c),n=new Int16Array(c,2),o=new Uint32Array(c,4),p=new Float64Array(c,8),m=new Array(r),l=[],M=new Array(r);for(let i=0;i{let E=_.id;for(m[_.id]=_.trie;l.length>0;){let X=await y(D,{type:1,a:E,b:l.pop(),counts:o,maxes:n,mins:a,sums:p,tries:m});for(let A of X.ids)m[A]=X.tries[A]}return l.push(E),D.terminate()})}await Promise.all(M),await u.close();let R=x(I,{fd:I.length<1?v.fd:void 0,flags:"a",highWaterMark:1048576}),h=Buffer.allocUnsafe(100);R.write("{"),O(m,h,l[0],R,", ",s),R.end(`} -`);function s(i,D,_,E){let X=Math.round(p[E<<1]/o[E<<2]);i.write(D.toString("utf8",0,_)),i.write("="),i.write((a[E<<3]/10).toFixed(1)),i.write("/"),i.write((X/10).toFixed(1)),i.write("/"),i.write((n[E<<3]/10).toFixed(1))}}import{createReadStream as F}from"node:fs";var P=11*48,q=111*48;function H(e,t,r){return e[t]===45?(++t,t+4>r?P-10*e[t]-e[t+2]:q-100*e[t]-10*e[t+1]-e[t+3]):t+4>r?10*e[t]+e[t+2]-P:100*e[t]+10*e[t+1]+e[t+3]-q}async function k({end:e,fd:t,id:r,start:I,counts:u,maxes:f,mins:c,sums:a}){if(I>=e)return{id:r,trie:g(r,0)};let n=g(r),o=r*1e4+1,p=Buffer.allocUnsafe(107),m={autoClose:!1,fd:t,start:I,end:e-1,highWaterMark:L(e-I)},l=-1,M;for await(let s of F("",m)){let i=s.length;for(let D=0;D=i?f[s]:i,++u[s>>1],a[s>>2]+=i}return{id:r,trie:n}}function B({a:e,b:t,tries:r,counts:I,maxes:u,mins:f,sums:c}){function a(o,p){o<<=3,p<<=3,f[o]=Math.min(f[o],f[p]),u[o]=Math.max(u[o],u[p]),I[o>>1]+=I[p>>1],c[o>>2]+=c[p>>2]}return{ids:S(r,e,t,a),tries:r}}if(K){let e=G(import.meta.url);U(process.argv[2],e,V())}else b.addListener("message",async e=>{if(e.type===0)b.postMessage(await k(e));else if(e.type===1)b.postMessage(B(e));else throw new Error("Unknown message type")}); +import{availableParallelism as V}from"node:os";import{fileURLToPath as G}from"node:url";import{isMainThread as K,parentPort as w}from"node:worker_threads";import{createWriteStream as x}from"node:fs";import{open as Z}from"node:fs/promises";import{stdout as v}from"node:process";function y(e,t,r){return e>t?e<=r?e:r:t}async function A(e,t,r,a=0){let u=(await e.stat()).size,s=Math.max(a,Math.floor(u/t)),i=Buffer.allocUnsafe(r),f=[],n=0;for(let o=s;o=0&&le.length&&(e=T(e,s+218)),e[0]+=218,e[u+0]=s,e[s+0]=e[1]),u=s}return[e,u]}function d(e=0,t=655360){t=Math.max(219,t);let r=new Int32Array(new SharedArrayBuffer(t<<2));return r[0]=219,r[1]=e,r}function T(e,t=0){let r=e[0];t=Math.max(t,Math.ceil(r*1.618033988749895));let a=new Int32Array(new SharedArrayBuffer(t<<2));for(let u=0;ue[n].length&&(e[n]=T(e[n],D+2),u.push(n)),e[n][0]+=2,e[n][o+0]=D,e[n][D+0]=h,e[n][D+1]=m;else{let R=e[n][D+0];n!==R&&(D=e[n][D+1]),s.push([R,D,h,m])}}o+=1,l+=1}}s.splice(0,i)}while(s.length>0);return u}function O(e,t,r,a,u="",s){let i=new Array(t.length+1);i[0]=[r,3,0];let f=0,n=!1;do{let[o,I,l]=i[f];if(l>=216){--f;continue}i[f][1]+=1,++i[f][2];let c=e[o][I+0];if(c===0)continue;let M=e[o][c+0];o!==M&&(c=e[o][c+1],o=M),t[f]=l+32,i[++f]=[o,c+2,0];let m=e[o][c+1];m!==0&&(n&&a.write(u),n=!0,s(a,t,f,m))}while(f>=0)}import{Worker as W}from"node:worker_threads";function U(e){let t=new W(e);return t.on("error",r=>{throw r}),t.on("messageerror",r=>{throw r}),t.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${t.threadId} exited with code ${r}`)}),t}function g(e,t){return new Promise(r=>{e.once("message",r),e.postMessage(t)})}async function C(e,t,r,a=""){r=y(r,1,512);let u=await Z(e,"r"),s=await A(u,r,107,16384);r=s.length;let i=new SharedArrayBuffer(1e4*r+1<<4),f=new Int16Array(i),n=new Int16Array(i,2),o=new Uint32Array(i,4),I=new Float64Array(i,8),l=new Array(r),c=[],M=new Array(r);for(let R=0;R{let E=_.id;for(l[_.id]=_.trie;c.length>0;){let X=await g(p,{type:1,a:E,b:c.pop(),counts:o,maxes:n,mins:f,sums:I,tries:l});for(let b of X.ids)l[b]=X.tries[b]}return c.push(E),p.terminate()})}await Promise.all(M),await u.close();let m=x(a,{fd:a.length<1?v.fd:void 0,flags:"a",highWaterMark:1048576}),h=Buffer.allocUnsafe(100);m.write("{"),O(l,h,c[0],m,", ",D),m.end(`} +`);function D(R,p,_,E){let X=Math.round(I[E<<1]/o[E<<2]);R.write(p.toString("utf8",0,_)),R.write("="),R.write((f[E<<3]/10).toFixed(1)),R.write("/"),R.write((X/10).toFixed(1)),R.write("/"),R.write((n[E<<3]/10).toFixed(1))}}import{open as F}from"fs/promises";var P=11*48,q=111*48;function H(e,t,r){return e[t]===45?(++t,t+4>r?P-10*e[t]-e[t+2]:q-100*e[t]-10*e[t+1]-e[t+3]):t+4>r?10*e[t]+e[t+2]-P:100*e[t]+10*e[t+1]+e[t+3]-q}async function k({end:e,filePath:t,id:r,start:a,counts:u,maxes:s,mins:i,sums:f}){if(a>=e)return{id:r,trie:d(r,0)};let n=d(r),o=r*1e4+1,I=await F(t,"r"),l=L(e-a),c=Buffer.allocUnsafe(l+107),M=0,m=0,h;for(;a=_?s[p]:_,++u[p>>1],f[p>>2]+=_}return await I.close(),{id:r,trie:n}}function B({a:e,b:t,tries:r,counts:a,maxes:u,mins:s,sums:i}){function f(o,I){o<<=3,I<<=3,s[o]=Math.min(s[o],s[I]),u[o]=Math.max(u[o],u[I]),a[o>>1]+=a[I>>1],i[o>>2]+=i[I>>2]}return{ids:S(r,e,t,f),tries:r}}if(K){let e=G(import.meta.url);C(process.argv[2],e,V())}else w.addListener("message",async e=>{if(e.type===0)w.postMessage(await k(e));else if(e.type===1)w.postMessage(B(e));else throw new Error("Unknown message type")}); //# sourceMappingURL=index.mjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index e9b1c21..e5b483c 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../src/index.ts", "../src/main.ts", "../src/utils/stream.ts", "../src/utils/utf8Trie.ts", "../src/utils/worker.ts", "../src/worker.ts", "../src/utils/parse.ts"], - "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport { RequestType, type Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === RequestType.PROCESS) {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === RequestType.MERGE) {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { WriteStream, createWriteStream } from \"node:fs\";\nimport { open } from \"node:fs/promises\";\nimport { stdout } from \"node:process\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\nimport { RequestType } from \"./types/request\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Open the given file\n const file = await open(filePath, \"r\");\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n file,\n maxWorkers,\n BRC.MAX_ENTRY_LEN,\n Config.CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: RequestType.PROCESS,\n counts,\n end: chunks[i][1],\n fd: file.fd,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[res.id] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: RequestType.MERGE,\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Close the file\n await file.close();\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? stdout.fd : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { FileHandle } from \"fs/promises\";\n\nimport { Config } from \"../constants/config\";\nimport { CharCode } from \"../constants/utf8\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n file: FileHandle,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CharCode.NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= Config.HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, Config.HIGH_WATER_MARK_MIN, Config.HIGH_WATER_MARK_MAX);\n}\n", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown: number[] = [];\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.push(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return grown;\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"node:worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { createReadStream } from \"node:fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n fd,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * BRC.MAX_STATIONS + 1;\n const buffer = Buffer.allocUnsafe(BRC.MAX_ENTRY_LEN);\n\n // Create readstream options\n const opts = {\n autoClose: false,\n fd,\n start,\n end: end - 1,\n highWaterMark: getHighWaterMark(end - start),\n };\n\n // For each chunk\n let bufI = -1;\n let leaf: number;\n for await (const chunk of createReadStream(\"\", opts)) {\n // For each byte\n const N = chunk.length;\n for (let i = 0; i < N; ++i) {\n // Add byte to buffer\n buffer[++bufI] = chunk[i];\n\n // If newline\n if (chunk[i] === CharCode.NEWLINE) {\n // Get semicolon\n let semI = bufI - 5;\n if (buffer[semI] !== CharCode.SEMICOLON) {\n semI += 1 | (1 + ~(buffer[semI - 1] === CharCode.SEMICOLON));\n }\n\n // Get temperature\n const tempV = parseDouble(buffer, semI + 1, bufI);\n bufI = -1;\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, buffer, 0, semI);\n\n // If the station existed\n if (trie[leaf + TrieNodeProto.VALUE_IDX] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf + TrieNodeProto.VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TrieNodeProto.VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], - "mappings": "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", - "names": ["availableParallelism", "fileURLToPath", "isMainThread", "parentPort", "createWriteStream", "open", "stdout", "clamp", "value", "min", "max", "getFileChunks", "file", "target", "maxLineLength", "minSize", "size", "chunkSize", "buffer", "chunks", "start", "end", "res", "newline", "getHighWaterMark", "add", "trie", "key", "min", "max", "index", "child", "grow", "createTrie", "id", "size", "trie", "grow", "minSize", "length", "next", "i", "mergeLeft", "tries", "at", "bt", "mergeFn", "grown", "queue", "Q", "q", "ai", "bi", "bvi", "avi", "bn", "ri", "rt", "li", "lt", "print", "key", "trieIndex", "stream", "separator", "callbackFn", "stack", "top", "tail", "trieI", "childPtr", "numChild", "childI", "childTrieI", "valueIndex", "Worker", "createWorker", "workerPath", "worker", "err", "code", "exec", "req", "resolve", "run", "filePath", "workerPath", "maxWorkers", "outPath", "clamp", "file", "open", "chunks", "getFileChunks", "valBuf", "mins", "maxes", "counts", "sums", "tries", "unmerged", "tasks", "worker", "createWorker", "exec", "res", "a", "id", "out", "createWriteStream", "stdout", "buffer", "print", "printStation", "stream", "name", "nameLen", "vi", "avg", "createReadStream", "CHAR_ZERO_11", "CHAR_ZERO_111", "parseDouble", "b", "min", "max", "run", "end", "fd", "id", "start", "counts", "maxes", "mins", "sums", "createTrie", "trie", "stations", "buffer", "opts", "getHighWaterMark", "bufI", "leaf", "chunk", "createReadStream", "N", "i", "semI", "tempV", "parseDouble", "add", "updateStation", "newStation", "index", "temp", "merge", "a", "b", "tries", "mergeStations", "ai", "bi", "mergeLeft", "isMainThread", "workerPath", "fileURLToPath", "run", "availableParallelism", "parentPort", "msg", "merge"] + "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport { RequestType, type Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === RequestType.PROCESS) {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === RequestType.MERGE) {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { WriteStream, createWriteStream } from \"node:fs\";\nimport { open } from \"node:fs/promises\";\nimport { stdout } from \"node:process\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\nimport { RequestType } from \"./types/request\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Open the given file\n const file = await open(filePath, \"r\");\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n file,\n maxWorkers,\n BRC.MAX_ENTRY_LEN,\n Config.CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: RequestType.PROCESS,\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[res.id] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: RequestType.MERGE,\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Close the file\n await file.close();\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? stdout.fd : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { FileHandle } from \"fs/promises\";\n\nimport { Config } from \"../constants/config\";\nimport { CharCode } from \"../constants/utf8\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n file: FileHandle,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CharCode.NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= Config.HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, Config.HIGH_WATER_MARK_MIN, Config.HIGH_WATER_MARK_MAX);\n}\n", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown: number[] = [];\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.push(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return grown;\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"node:worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { open } from \"fs/promises\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * BRC.MAX_STATIONS + 1;\n\n const file = await open(filePath, \"r\");\n const chunkSize = getHighWaterMark(end - start);\n const chunk = Buffer.allocUnsafe(chunkSize + BRC.MAX_ENTRY_LEN);\n\n // For each chunk\n let i = 0;\n let minI = 0;\n let leaf: number;\n while (start < end) {\n const res = await file.read(chunk, i, chunkSize, start);\n start += res.bytesRead;\n\n for (const N = i + res.bytesRead; i < N; ++i) {\n // If newline\n if (chunk[i] === CharCode.NEWLINE) {\n\n // Get semicolon\n let semI = i - 5;\n if (chunk[semI] !== CharCode.SEMICOLON) {\n semI += 1 | (1 + ~(chunk[semI - 1] === CharCode.SEMICOLON));\n }\n\n // Get temperature\n const tempV = parseDouble(chunk, semI + 1, i);\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, chunk, minI, semI);\n minI = i + 1;\n\n // If the station existed\n if (trie[leaf + TrieNodeProto.VALUE_IDX] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf + TrieNodeProto.VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TrieNodeProto.VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n chunk.copyWithin(0, minI, i);\n i -= minI;\n minI = 0;\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n await file.close();\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], + "mappings": "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", + "names": ["availableParallelism", "fileURLToPath", "isMainThread", "parentPort", "createWriteStream", "open", "stdout", "clamp", "value", "min", "max", "getFileChunks", "file", "target", "maxLineLength", "minSize", "size", "chunkSize", "buffer", "chunks", "start", "end", "res", "newline", "getHighWaterMark", "add", "trie", "key", "min", "max", "index", "child", "grow", "createTrie", "id", "size", "trie", "grow", "minSize", "length", "next", "i", "mergeLeft", "tries", "at", "bt", "mergeFn", "grown", "queue", "Q", "q", "ai", "bi", "bvi", "avi", "bn", "ri", "rt", "li", "lt", "print", "key", "trieIndex", "stream", "separator", "callbackFn", "stack", "top", "tail", "trieI", "childPtr", "numChild", "childI", "childTrieI", "valueIndex", "Worker", "createWorker", "workerPath", "worker", "err", "code", "exec", "req", "resolve", "run", "filePath", "workerPath", "maxWorkers", "outPath", "clamp", "file", "open", "chunks", "getFileChunks", "valBuf", "mins", "maxes", "counts", "sums", "tries", "unmerged", "tasks", "i", "worker", "createWorker", "exec", "res", "a", "id", "out", "createWriteStream", "stdout", "buffer", "print", "printStation", "stream", "name", "nameLen", "vi", "avg", "open", "CHAR_ZERO_11", "CHAR_ZERO_111", "parseDouble", "b", "min", "max", "run", "end", "filePath", "id", "start", "counts", "maxes", "mins", "sums", "createTrie", "trie", "stations", "file", "open", "chunkSize", "getHighWaterMark", "chunk", "i", "minI", "leaf", "res", "N", "semI", "tempV", "parseDouble", "add", "updateStation", "newStation", "index", "temp", "merge", "a", "b", "tries", "mergeStations", "ai", "bi", "mergeLeft", "isMainThread", "workerPath", "fileURLToPath", "run", "availableParallelism", "parentPort", "msg", "merge"] } diff --git a/src/main/nodejs/havelessbemore/src/main.ts b/src/main/nodejs/havelessbemore/src/main.ts index 014135a..8a14f74 100644 --- a/src/main/nodejs/havelessbemore/src/main.ts +++ b/src/main/nodejs/havelessbemore/src/main.ts @@ -58,7 +58,7 @@ export async function run( type: RequestType.PROCESS, counts, end: chunks[i][1], - fd: file.fd, + filePath, id: i, maxes, mins, diff --git a/src/main/nodejs/havelessbemore/src/types/processRequest.ts b/src/main/nodejs/havelessbemore/src/types/processRequest.ts index 7936108..f4ad6aa 100644 --- a/src/main/nodejs/havelessbemore/src/types/processRequest.ts +++ b/src/main/nodejs/havelessbemore/src/types/processRequest.ts @@ -3,7 +3,7 @@ import { Request, RequestType } from "./request"; export interface ProcessRequest extends Request { type: RequestType.PROCESS; end: number; - fd: number; + filePath: string, id: number; start: number; // Shared memory diff --git a/src/main/nodejs/havelessbemore/src/worker.ts b/src/main/nodejs/havelessbemore/src/worker.ts index 7188aad..acc8cdb 100644 --- a/src/main/nodejs/havelessbemore/src/worker.ts +++ b/src/main/nodejs/havelessbemore/src/worker.ts @@ -1,4 +1,4 @@ -import { createReadStream } from "node:fs"; +import { open } from "fs/promises"; import type { MergeRequest } from "./types/mergeRequest"; import type { MergeResponse } from "./types/mergeResponse"; @@ -13,7 +13,7 @@ import { add, createTrie, mergeLeft } from "./utils/utf8Trie"; export async function run({ end, - fd, + filePath, id, start, // Shared memory @@ -30,41 +30,35 @@ export async function run({ // Initialize constants let trie = createTrie(id); let stations = id * BRC.MAX_STATIONS + 1; - const buffer = Buffer.allocUnsafe(BRC.MAX_ENTRY_LEN); - // Create readstream options - const opts = { - autoClose: false, - fd, - start, - end: end - 1, - highWaterMark: getHighWaterMark(end - start), - }; + const file = await open(filePath, "r"); + const chunkSize = getHighWaterMark(end - start); + const chunk = Buffer.allocUnsafe(chunkSize + BRC.MAX_ENTRY_LEN); // For each chunk - let bufI = -1; + let i = 0; + let minI = 0; let leaf: number; - for await (const chunk of createReadStream("", opts)) { - // For each byte - const N = chunk.length; - for (let i = 0; i < N; ++i) { - // Add byte to buffer - buffer[++bufI] = chunk[i]; + while (start < end) { + const res = await file.read(chunk, i, chunkSize, start); + start += res.bytesRead; + for (const N = i + res.bytesRead; i < N; ++i) { // If newline if (chunk[i] === CharCode.NEWLINE) { + // Get semicolon - let semI = bufI - 5; - if (buffer[semI] !== CharCode.SEMICOLON) { - semI += 1 | (1 + ~(buffer[semI - 1] === CharCode.SEMICOLON)); + let semI = i - 5; + if (chunk[semI] !== CharCode.SEMICOLON) { + semI += 1 | (1 + ~(chunk[semI - 1] === CharCode.SEMICOLON)); } // Get temperature - const tempV = parseDouble(buffer, semI + 1, bufI); - bufI = -1; + const tempV = parseDouble(chunk, semI + 1, i); // Add the station's name to the trie and get leaf index - [trie, leaf] = add(trie, buffer, 0, semI); + [trie, leaf] = add(trie, chunk, minI, semI); + minI = i + 1; // If the station existed if (trie[leaf + TrieNodeProto.VALUE_IDX] !== Trie.NULL) { @@ -77,6 +71,9 @@ export async function run({ } } } + chunk.copyWithin(0, minI, i); + i -= minI; + minI = 0; } function newStation(index: number, temp: number): void { @@ -94,6 +91,7 @@ export async function run({ sums[index >> 2] += temp; } + await file.close(); return { id, trie }; } From 7a4ed23a49acf8ce6a846b9e07709e4520d839ca Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Sun, 26 May 2024 17:34:55 -0400 Subject: [PATCH 55/69] Format files --- src/main/nodejs/havelessbemore/dist/index.mjs.map | 4 ++-- src/main/nodejs/havelessbemore/src/types/processRequest.ts | 2 +- src/main/nodejs/havelessbemore/src/worker.ts | 1 - 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index e5b483c..ae0b3ed 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../src/index.ts", "../src/main.ts", "../src/utils/stream.ts", "../src/utils/utf8Trie.ts", "../src/utils/worker.ts", "../src/worker.ts", "../src/utils/parse.ts"], - "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport { RequestType, type Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === RequestType.PROCESS) {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === RequestType.MERGE) {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { WriteStream, createWriteStream } from \"node:fs\";\nimport { open } from \"node:fs/promises\";\nimport { stdout } from \"node:process\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\nimport { RequestType } from \"./types/request\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Open the given file\n const file = await open(filePath, \"r\");\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n file,\n maxWorkers,\n BRC.MAX_ENTRY_LEN,\n Config.CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: RequestType.PROCESS,\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[res.id] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: RequestType.MERGE,\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Close the file\n await file.close();\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? stdout.fd : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { FileHandle } from \"fs/promises\";\n\nimport { Config } from \"../constants/config\";\nimport { CharCode } from \"../constants/utf8\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n file: FileHandle,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CharCode.NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= Config.HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, Config.HIGH_WATER_MARK_MIN, Config.HIGH_WATER_MARK_MAX);\n}\n", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown: number[] = [];\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.push(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return grown;\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"node:worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { open } from \"fs/promises\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * BRC.MAX_STATIONS + 1;\n\n const file = await open(filePath, \"r\");\n const chunkSize = getHighWaterMark(end - start);\n const chunk = Buffer.allocUnsafe(chunkSize + BRC.MAX_ENTRY_LEN);\n\n // For each chunk\n let i = 0;\n let minI = 0;\n let leaf: number;\n while (start < end) {\n const res = await file.read(chunk, i, chunkSize, start);\n start += res.bytesRead;\n\n for (const N = i + res.bytesRead; i < N; ++i) {\n // If newline\n if (chunk[i] === CharCode.NEWLINE) {\n\n // Get semicolon\n let semI = i - 5;\n if (chunk[semI] !== CharCode.SEMICOLON) {\n semI += 1 | (1 + ~(chunk[semI - 1] === CharCode.SEMICOLON));\n }\n\n // Get temperature\n const tempV = parseDouble(chunk, semI + 1, i);\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, chunk, minI, semI);\n minI = i + 1;\n\n // If the station existed\n if (trie[leaf + TrieNodeProto.VALUE_IDX] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf + TrieNodeProto.VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TrieNodeProto.VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n chunk.copyWithin(0, minI, i);\n i -= minI;\n minI = 0;\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n await file.close();\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], - "mappings": "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", + "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport { RequestType, type Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === RequestType.PROCESS) {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === RequestType.MERGE) {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { WriteStream, createWriteStream } from \"node:fs\";\nimport { open } from \"node:fs/promises\";\nimport { stdout } from \"node:process\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\nimport { RequestType } from \"./types/request\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Open the given file\n const file = await open(filePath, \"r\");\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n file,\n maxWorkers,\n BRC.MAX_ENTRY_LEN,\n Config.CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: RequestType.PROCESS,\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[res.id] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: RequestType.MERGE,\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Close the file\n await file.close();\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? stdout.fd : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { FileHandle } from \"fs/promises\";\n\nimport { Config } from \"../constants/config\";\nimport { CharCode } from \"../constants/utf8\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n file: FileHandle,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CharCode.NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= Config.HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, Config.HIGH_WATER_MARK_MIN, Config.HIGH_WATER_MARK_MAX);\n}\n", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown: number[] = [];\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.push(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return grown;\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"node:worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { open } from \"fs/promises\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * BRC.MAX_STATIONS + 1;\n\n const file = await open(filePath, \"r\");\n const chunkSize = getHighWaterMark(end - start);\n const chunk = Buffer.allocUnsafe(chunkSize + BRC.MAX_ENTRY_LEN);\n\n // For each chunk\n let i = 0;\n let minI = 0;\n let leaf: number;\n while (start < end) {\n const res = await file.read(chunk, i, chunkSize, start);\n start += res.bytesRead;\n\n for (const N = i + res.bytesRead; i < N; ++i) {\n // If newline\n if (chunk[i] === CharCode.NEWLINE) {\n // Get semicolon\n let semI = i - 5;\n if (chunk[semI] !== CharCode.SEMICOLON) {\n semI += 1 | (1 + ~(chunk[semI - 1] === CharCode.SEMICOLON));\n }\n\n // Get temperature\n const tempV = parseDouble(chunk, semI + 1, i);\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, chunk, minI, semI);\n minI = i + 1;\n\n // If the station existed\n if (trie[leaf + TrieNodeProto.VALUE_IDX] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf + TrieNodeProto.VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TrieNodeProto.VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n chunk.copyWithin(0, minI, i);\n i -= minI;\n minI = 0;\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n await file.close();\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], + "mappings": "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", "names": ["availableParallelism", "fileURLToPath", "isMainThread", "parentPort", "createWriteStream", "open", "stdout", "clamp", "value", "min", "max", "getFileChunks", "file", "target", "maxLineLength", "minSize", "size", "chunkSize", "buffer", "chunks", "start", "end", "res", "newline", "getHighWaterMark", "add", "trie", "key", "min", "max", "index", "child", "grow", "createTrie", "id", "size", "trie", "grow", "minSize", "length", "next", "i", "mergeLeft", "tries", "at", "bt", "mergeFn", "grown", "queue", "Q", "q", "ai", "bi", "bvi", "avi", "bn", "ri", "rt", "li", "lt", "print", "key", "trieIndex", "stream", "separator", "callbackFn", "stack", "top", "tail", "trieI", "childPtr", "numChild", "childI", "childTrieI", "valueIndex", "Worker", "createWorker", "workerPath", "worker", "err", "code", "exec", "req", "resolve", "run", "filePath", "workerPath", "maxWorkers", "outPath", "clamp", "file", "open", "chunks", "getFileChunks", "valBuf", "mins", "maxes", "counts", "sums", "tries", "unmerged", "tasks", "i", "worker", "createWorker", "exec", "res", "a", "id", "out", "createWriteStream", "stdout", "buffer", "print", "printStation", "stream", "name", "nameLen", "vi", "avg", "open", "CHAR_ZERO_11", "CHAR_ZERO_111", "parseDouble", "b", "min", "max", "run", "end", "filePath", "id", "start", "counts", "maxes", "mins", "sums", "createTrie", "trie", "stations", "file", "open", "chunkSize", "getHighWaterMark", "chunk", "i", "minI", "leaf", "res", "N", "semI", "tempV", "parseDouble", "add", "updateStation", "newStation", "index", "temp", "merge", "a", "b", "tries", "mergeStations", "ai", "bi", "mergeLeft", "isMainThread", "workerPath", "fileURLToPath", "run", "availableParallelism", "parentPort", "msg", "merge"] } diff --git a/src/main/nodejs/havelessbemore/src/types/processRequest.ts b/src/main/nodejs/havelessbemore/src/types/processRequest.ts index f4ad6aa..06f566a 100644 --- a/src/main/nodejs/havelessbemore/src/types/processRequest.ts +++ b/src/main/nodejs/havelessbemore/src/types/processRequest.ts @@ -3,7 +3,7 @@ import { Request, RequestType } from "./request"; export interface ProcessRequest extends Request { type: RequestType.PROCESS; end: number; - filePath: string, + filePath: string; id: number; start: number; // Shared memory diff --git a/src/main/nodejs/havelessbemore/src/worker.ts b/src/main/nodejs/havelessbemore/src/worker.ts index acc8cdb..e7b27ab 100644 --- a/src/main/nodejs/havelessbemore/src/worker.ts +++ b/src/main/nodejs/havelessbemore/src/worker.ts @@ -46,7 +46,6 @@ export async function run({ for (const N = i + res.bytesRead; i < N; ++i) { // If newline if (chunk[i] === CharCode.NEWLINE) { - // Get semicolon let semI = i - 5; if (chunk[semI] !== CharCode.SEMICOLON) { From 8d24cdef199fec7c7eba95320e1f17f7fefdca68 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Sun, 26 May 2024 17:50:41 -0400 Subject: [PATCH 56/69] Update benchmark results --- src/main/nodejs/havelessbemore/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/nodejs/havelessbemore/README.md b/src/main/nodejs/havelessbemore/README.md index a143f8a..d524569 100644 --- a/src/main/nodejs/havelessbemore/README.md +++ b/src/main/nodejs/havelessbemore/README.md @@ -14,9 +14,9 @@ ### Results -- Min: 13.0s -- Avg: 13.8s -- Max: 14.2s +- Min: 12.0s +- Avg: 12.8s +- Max: 13.1s - Samples: 10 runs, 5s apart #### Specs: From b7c7f1970e36a5a7975b5931b62b1a58110b3cdd Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Sun, 26 May 2024 22:11:57 -0400 Subject: [PATCH 57/69] Remove config constant CHUNK_SIZE_MIN --- src/main/nodejs/havelessbemore/dist/index.mjs | 4 ++-- src/main/nodejs/havelessbemore/dist/index.mjs.map | 2 +- src/main/nodejs/havelessbemore/src/constants/config.ts | 8 +------- src/main/nodejs/havelessbemore/src/constants/utf8.ts | 4 ++-- src/main/nodejs/havelessbemore/src/main.ts | 2 +- 5 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index 42d5460..11362ae 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -1,3 +1,3 @@ -import{availableParallelism as V}from"node:os";import{fileURLToPath as G}from"node:url";import{isMainThread as K,parentPort as w}from"node:worker_threads";import{createWriteStream as x}from"node:fs";import{open as Z}from"node:fs/promises";import{stdout as v}from"node:process";function y(e,t,r){return e>t?e<=r?e:r:t}async function A(e,t,r,a=0){let u=(await e.stat()).size,s=Math.max(a,Math.floor(u/t)),i=Buffer.allocUnsafe(r),f=[],n=0;for(let o=s;o=0&&le.length&&(e=T(e,s+218)),e[0]+=218,e[u+0]=s,e[s+0]=e[1]),u=s}return[e,u]}function d(e=0,t=655360){t=Math.max(219,t);let r=new Int32Array(new SharedArrayBuffer(t<<2));return r[0]=219,r[1]=e,r}function T(e,t=0){let r=e[0];t=Math.max(t,Math.ceil(r*1.618033988749895));let a=new Int32Array(new SharedArrayBuffer(t<<2));for(let u=0;ue[n].length&&(e[n]=T(e[n],D+2),u.push(n)),e[n][0]+=2,e[n][o+0]=D,e[n][D+0]=h,e[n][D+1]=m;else{let R=e[n][D+0];n!==R&&(D=e[n][D+1]),s.push([R,D,h,m])}}o+=1,l+=1}}s.splice(0,i)}while(s.length>0);return u}function O(e,t,r,a,u="",s){let i=new Array(t.length+1);i[0]=[r,3,0];let f=0,n=!1;do{let[o,I,l]=i[f];if(l>=216){--f;continue}i[f][1]+=1,++i[f][2];let c=e[o][I+0];if(c===0)continue;let M=e[o][c+0];o!==M&&(c=e[o][c+1],o=M),t[f]=l+32,i[++f]=[o,c+2,0];let m=e[o][c+1];m!==0&&(n&&a.write(u),n=!0,s(a,t,f,m))}while(f>=0)}import{Worker as W}from"node:worker_threads";function U(e){let t=new W(e);return t.on("error",r=>{throw r}),t.on("messageerror",r=>{throw r}),t.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${t.threadId} exited with code ${r}`)}),t}function g(e,t){return new Promise(r=>{e.once("message",r),e.postMessage(t)})}async function C(e,t,r,a=""){r=y(r,1,512);let u=await Z(e,"r"),s=await A(u,r,107,16384);r=s.length;let i=new SharedArrayBuffer(1e4*r+1<<4),f=new Int16Array(i),n=new Int16Array(i,2),o=new Uint32Array(i,4),I=new Float64Array(i,8),l=new Array(r),c=[],M=new Array(r);for(let R=0;R{let E=_.id;for(l[_.id]=_.trie;c.length>0;){let X=await g(p,{type:1,a:E,b:c.pop(),counts:o,maxes:n,mins:f,sums:I,tries:l});for(let b of X.ids)l[b]=X.tries[b]}return c.push(E),p.terminate()})}await Promise.all(M),await u.close();let m=x(a,{fd:a.length<1?v.fd:void 0,flags:"a",highWaterMark:1048576}),h=Buffer.allocUnsafe(100);m.write("{"),O(l,h,c[0],m,", ",D),m.end(`} -`);function D(R,p,_,E){let X=Math.round(I[E<<1]/o[E<<2]);R.write(p.toString("utf8",0,_)),R.write("="),R.write((f[E<<3]/10).toFixed(1)),R.write("/"),R.write((X/10).toFixed(1)),R.write("/"),R.write((n[E<<3]/10).toFixed(1))}}import{open as F}from"fs/promises";var P=11*48,q=111*48;function H(e,t,r){return e[t]===45?(++t,t+4>r?P-10*e[t]-e[t+2]:q-100*e[t]-10*e[t+1]-e[t+3]):t+4>r?10*e[t]+e[t+2]-P:100*e[t]+10*e[t+1]+e[t+3]-q}async function k({end:e,filePath:t,id:r,start:a,counts:u,maxes:s,mins:i,sums:f}){if(a>=e)return{id:r,trie:d(r,0)};let n=d(r),o=r*1e4+1,I=await F(t,"r"),l=L(e-a),c=Buffer.allocUnsafe(l+107),M=0,m=0,h;for(;a=_?s[p]:_,++u[p>>1],f[p>>2]+=_}return await I.close(),{id:r,trie:n}}function B({a:e,b:t,tries:r,counts:a,maxes:u,mins:s,sums:i}){function f(o,I){o<<=3,I<<=3,s[o]=Math.min(s[o],s[I]),u[o]=Math.max(u[o],u[I]),a[o>>1]+=a[I>>1],i[o>>2]+=i[I>>2]}return{ids:S(r,e,t,f),tries:r}}if(K){let e=G(import.meta.url);C(process.argv[2],e,V())}else w.addListener("message",async e=>{if(e.type===0)w.postMessage(await k(e));else if(e.type===1)w.postMessage(B(e));else throw new Error("Unknown message type")}); +import{availableParallelism as G}from"node:os";import{fileURLToPath as V}from"node:url";import{isMainThread as K,parentPort as w}from"node:worker_threads";import{createWriteStream as x}from"node:fs";import{open as v}from"node:fs/promises";import{stdout as F}from"node:process";function y(e,t,r){return e>t?e<=r?e:r:t}async function b(e,t,r,a=0){let u=(await e.stat()).size,s=Math.max(a,Math.floor(u/t)),i=Buffer.allocUnsafe(r),f=[],n=0;for(let o=s;o=0&&le.length&&(e=T(e,s+218)),e[0]+=218,e[u+0]=s,e[s+0]=e[1]),u=s}return[e,u]}function d(e=0,t=655360){t=Math.max(219,t);let r=new Int32Array(new SharedArrayBuffer(t<<2));return r[0]=219,r[1]=e,r}function T(e,t=0){let r=e[0];t=Math.max(t,Math.ceil(r*1.618033988749895));let a=new Int32Array(new SharedArrayBuffer(t<<2));for(let u=0;ue[n].length&&(e[n]=T(e[n],D+2),u.push(n)),e[n][0]+=2,e[n][o+0]=D,e[n][D+0]=h,e[n][D+1]=m;else{let R=e[n][D+0];n!==R&&(D=e[n][D+1]),s.push([R,D,h,m])}}o+=1,l+=1}}s.splice(0,i)}while(s.length>0);return u}function O(e,t,r,a,u="",s){let i=new Array(t.length+1);i[0]=[r,3,0];let f=0,n=!1;do{let[o,I,l]=i[f];if(l>=216){--f;continue}i[f][1]+=1,++i[f][2];let c=e[o][I+0];if(c===0)continue;let M=e[o][c+0];o!==M&&(c=e[o][c+1],o=M),t[f]=l+32,i[++f]=[o,c+2,0];let m=e[o][c+1];m!==0&&(n&&a.write(u),n=!0,s(a,t,f,m))}while(f>=0)}import{Worker as B}from"node:worker_threads";function U(e){let t=new B(e);return t.on("error",r=>{throw r}),t.on("messageerror",r=>{throw r}),t.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${t.threadId} exited with code ${r}`)}),t}function g(e,t){return new Promise(r=>{e.once("message",r),e.postMessage(t)})}async function C(e,t,r,a=""){r=y(r,1,512);let u=await v(e,"r"),s=await b(u,r,107,16384);r=s.length;let i=new SharedArrayBuffer(1e4*r+1<<4),f=new Int16Array(i),n=new Int16Array(i,2),o=new Uint32Array(i,4),I=new Float64Array(i,8),l=new Array(r),c=[],M=new Array(r);for(let R=0;R{let E=_.id;for(l[_.id]=_.trie;c.length>0;){let X=await g(p,{type:1,a:E,b:c.pop(),counts:o,maxes:n,mins:f,sums:I,tries:l});for(let A of X.ids)l[A]=X.tries[A]}return c.push(E),p.terminate()})}await Promise.all(M),await u.close();let m=x(a,{fd:a.length<1?F.fd:void 0,flags:"a",highWaterMark:1048576}),h=Buffer.allocUnsafe(100);m.write("{"),O(l,h,c[0],m,", ",D),m.end(`} +`);function D(R,p,_,E){let X=Math.round(I[E<<1]/o[E<<2]);R.write(p.toString("utf8",0,_)),R.write("="),R.write((f[E<<3]/10).toFixed(1)),R.write("/"),R.write((X/10).toFixed(1)),R.write("/"),R.write((n[E<<3]/10).toFixed(1))}}import{open as Z}from"fs/promises";var P=11*48,q=111*48;function H(e,t,r){return e[t]===45?(++t,t+4>r?P-10*e[t]-e[t+2]:q-100*e[t]-10*e[t+1]-e[t+3]):t+4>r?10*e[t]+e[t+2]-P:100*e[t]+10*e[t+1]+e[t+3]-q}async function W({end:e,filePath:t,id:r,start:a,counts:u,maxes:s,mins:i,sums:f}){if(a>=e)return{id:r,trie:d(r,0)};let n=d(r),o=r*1e4+1,I=await Z(t,"r"),l=L(e-a),c=Buffer.allocUnsafe(l+107),M=0,m=0,h;for(;a=_?s[p]:_,++u[p>>1],f[p>>2]+=_}return await I.close(),{id:r,trie:n}}function k({a:e,b:t,tries:r,counts:a,maxes:u,mins:s,sums:i}){function f(o,I){o<<=3,I<<=3,s[o]=Math.min(s[o],s[I]),u[o]=Math.max(u[o],u[I]),a[o>>1]+=a[I>>1],i[o>>2]+=i[I>>2]}return{ids:S(r,e,t,f),tries:r}}if(K){let e=V(import.meta.url);C(process.argv[2],e,G())}else w.addListener("message",async e=>{if(e.type===0)w.postMessage(await W(e));else if(e.type===1)w.postMessage(k(e));else throw new Error("Unknown message type")}); //# sourceMappingURL=index.mjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index ae0b3ed..2541ceb 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../src/index.ts", "../src/main.ts", "../src/utils/stream.ts", "../src/utils/utf8Trie.ts", "../src/utils/worker.ts", "../src/worker.ts", "../src/utils/parse.ts"], - "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport { RequestType, type Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === RequestType.PROCESS) {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === RequestType.MERGE) {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { WriteStream, createWriteStream } from \"node:fs\";\nimport { open } from \"node:fs/promises\";\nimport { stdout } from \"node:process\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\nimport { RequestType } from \"./types/request\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Open the given file\n const file = await open(filePath, \"r\");\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n file,\n maxWorkers,\n BRC.MAX_ENTRY_LEN,\n Config.CHUNK_SIZE_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: RequestType.PROCESS,\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[res.id] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: RequestType.MERGE,\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Close the file\n await file.close();\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? stdout.fd : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { FileHandle } from \"fs/promises\";\n\nimport { Config } from \"../constants/config\";\nimport { CharCode } from \"../constants/utf8\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n file: FileHandle,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CharCode.NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= Config.HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, Config.HIGH_WATER_MARK_MIN, Config.HIGH_WATER_MARK_MAX);\n}\n", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown: number[] = [];\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.push(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return grown;\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"node:worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { open } from \"fs/promises\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * BRC.MAX_STATIONS + 1;\n\n const file = await open(filePath, \"r\");\n const chunkSize = getHighWaterMark(end - start);\n const chunk = Buffer.allocUnsafe(chunkSize + BRC.MAX_ENTRY_LEN);\n\n // For each chunk\n let i = 0;\n let minI = 0;\n let leaf: number;\n while (start < end) {\n const res = await file.read(chunk, i, chunkSize, start);\n start += res.bytesRead;\n\n for (const N = i + res.bytesRead; i < N; ++i) {\n // If newline\n if (chunk[i] === CharCode.NEWLINE) {\n // Get semicolon\n let semI = i - 5;\n if (chunk[semI] !== CharCode.SEMICOLON) {\n semI += 1 | (1 + ~(chunk[semI - 1] === CharCode.SEMICOLON));\n }\n\n // Get temperature\n const tempV = parseDouble(chunk, semI + 1, i);\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, chunk, minI, semI);\n minI = i + 1;\n\n // If the station existed\n if (trie[leaf + TrieNodeProto.VALUE_IDX] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf + TrieNodeProto.VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TrieNodeProto.VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n chunk.copyWithin(0, minI, i);\n i -= minI;\n minI = 0;\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n await file.close();\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], + "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport { RequestType, type Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === RequestType.PROCESS) {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === RequestType.MERGE) {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { WriteStream, createWriteStream } from \"node:fs\";\nimport { open } from \"node:fs/promises\";\nimport { stdout } from \"node:process\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\nimport { RequestType } from \"./types/request\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Open the given file\n const file = await open(filePath, \"r\");\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n file,\n maxWorkers,\n BRC.MAX_ENTRY_LEN,\n Config.HIGH_WATER_MARK_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: RequestType.PROCESS,\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[res.id] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: RequestType.MERGE,\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Close the file\n await file.close();\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? stdout.fd : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { FileHandle } from \"fs/promises\";\n\nimport { Config } from \"../constants/config\";\nimport { CharCode } from \"../constants/utf8\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n file: FileHandle,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CharCode.NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= Config.HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, Config.HIGH_WATER_MARK_MIN, Config.HIGH_WATER_MARK_MAX);\n}\n", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown: number[] = [];\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.push(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return grown;\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"node:worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { open } from \"fs/promises\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * BRC.MAX_STATIONS + 1;\n\n const file = await open(filePath, \"r\");\n const chunkSize = getHighWaterMark(end - start);\n const chunk = Buffer.allocUnsafe(chunkSize + BRC.MAX_ENTRY_LEN);\n\n // For each chunk\n let i = 0;\n let minI = 0;\n let leaf: number;\n while (start < end) {\n const res = await file.read(chunk, i, chunkSize, start);\n start += res.bytesRead;\n\n for (const N = i + res.bytesRead; i < N; ++i) {\n // If newline\n if (chunk[i] === CharCode.NEWLINE) {\n // Get semicolon\n let semI = i - 5;\n if (chunk[semI] !== CharCode.SEMICOLON) {\n semI += 1 | (1 + ~(chunk[semI - 1] === CharCode.SEMICOLON));\n }\n\n // Get temperature\n const tempV = parseDouble(chunk, semI + 1, i);\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, chunk, minI, semI);\n minI = i + 1;\n\n // If the station existed\n if (trie[leaf + TrieNodeProto.VALUE_IDX] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf + TrieNodeProto.VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TrieNodeProto.VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n chunk.copyWithin(0, minI, i);\n i -= minI;\n minI = 0;\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n await file.close();\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], "mappings": "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", "names": ["availableParallelism", "fileURLToPath", "isMainThread", "parentPort", "createWriteStream", "open", "stdout", "clamp", "value", "min", "max", "getFileChunks", "file", "target", "maxLineLength", "minSize", "size", "chunkSize", "buffer", "chunks", "start", "end", "res", "newline", "getHighWaterMark", "add", "trie", "key", "min", "max", "index", "child", "grow", "createTrie", "id", "size", "trie", "grow", "minSize", "length", "next", "i", "mergeLeft", "tries", "at", "bt", "mergeFn", "grown", "queue", "Q", "q", "ai", "bi", "bvi", "avi", "bn", "ri", "rt", "li", "lt", "print", "key", "trieIndex", "stream", "separator", "callbackFn", "stack", "top", "tail", "trieI", "childPtr", "numChild", "childI", "childTrieI", "valueIndex", "Worker", "createWorker", "workerPath", "worker", "err", "code", "exec", "req", "resolve", "run", "filePath", "workerPath", "maxWorkers", "outPath", "clamp", "file", "open", "chunks", "getFileChunks", "valBuf", "mins", "maxes", "counts", "sums", "tries", "unmerged", "tasks", "i", "worker", "createWorker", "exec", "res", "a", "id", "out", "createWriteStream", "stdout", "buffer", "print", "printStation", "stream", "name", "nameLen", "vi", "avg", "open", "CHAR_ZERO_11", "CHAR_ZERO_111", "parseDouble", "b", "min", "max", "run", "end", "filePath", "id", "start", "counts", "maxes", "mins", "sums", "createTrie", "trie", "stations", "file", "open", "chunkSize", "getHighWaterMark", "chunk", "i", "minI", "leaf", "res", "N", "semI", "tempV", "parseDouble", "add", "updateStation", "newStation", "index", "temp", "merge", "a", "b", "tries", "mergeStations", "ai", "bi", "mergeLeft", "isMainThread", "workerPath", "fileURLToPath", "run", "availableParallelism", "parentPort", "msg", "merge"] } diff --git a/src/main/nodejs/havelessbemore/src/constants/config.ts b/src/main/nodejs/havelessbemore/src/constants/config.ts index 7cea1e6..7f6ccab 100644 --- a/src/main/nodejs/havelessbemore/src/constants/config.ts +++ b/src/main/nodejs/havelessbemore/src/constants/config.ts @@ -22,11 +22,6 @@ export const enum Config { */ HIGH_WATER_MARK_RATIO = 0.00625, - /** - * The minimum size in bytes of a file chunk. - */ - CHUNK_SIZE_MIN = HIGH_WATER_MARK_MIN, - /** * The minimum number of web workers (inclusive). */ @@ -45,8 +40,7 @@ export const enum Config { * * There is not much basis for the current value. * Development was done with at most 8 workers and - * a reasonable input file, with memory never exceeding - * 20 MiB total across all workers. + * a reasonable input file. * * In theory, the challenge constraints allow for input * files that would require each worker using upwards of diff --git a/src/main/nodejs/havelessbemore/src/constants/utf8.ts b/src/main/nodejs/havelessbemore/src/constants/utf8.ts index 6fa19ad..45f3846 100644 --- a/src/main/nodejs/havelessbemore/src/constants/utf8.ts +++ b/src/main/nodejs/havelessbemore/src/constants/utf8.ts @@ -37,14 +37,14 @@ export const enum UTF8 { * * @see {@link https://en.wikipedia.org/wiki/Unicode_control_characters#Category_%22Cc%22_control_codes_(C0_and_C1) | Control Codes} */ - BYTE_MIN = 32, + BYTE_MIN = 0x20, /** * The maximum value of a UTF-8 byte. * * @see {@link https://en.wikipedia.org/wiki/UTF-8#Encoding | UTF-8 Encoding} */ - BYTE_MAX = 0b11110111, + BYTE_MAX = 0xf7, /** * The number of possible values in a UTF-8 byte. diff --git a/src/main/nodejs/havelessbemore/src/main.ts b/src/main/nodejs/havelessbemore/src/main.ts index 8a14f74..4cf6a7c 100644 --- a/src/main/nodejs/havelessbemore/src/main.ts +++ b/src/main/nodejs/havelessbemore/src/main.ts @@ -31,7 +31,7 @@ export async function run( file, maxWorkers, BRC.MAX_ENTRY_LEN, - Config.CHUNK_SIZE_MIN, + Config.HIGH_WATER_MARK_MIN, ); // Adjust the number of workers to the number of chunks From 1a3de36de13e8a465688343ad939791350d3ec16 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Mon, 27 May 2024 00:06:19 -0400 Subject: [PATCH 58/69] Replace fs/promises with sync fs functions --- src/main/nodejs/havelessbemore/dist/index.mjs | 4 ++-- src/main/nodejs/havelessbemore/dist/index.mjs.map | 6 +++--- src/main/nodejs/havelessbemore/src/main.ts | 13 ++++++------- .../nodejs/havelessbemore/src/utils/stream.ts | 15 +++++++-------- 4 files changed, 18 insertions(+), 20 deletions(-) diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index 11362ae..a9541aa 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -1,3 +1,3 @@ -import{availableParallelism as G}from"node:os";import{fileURLToPath as V}from"node:url";import{isMainThread as K,parentPort as w}from"node:worker_threads";import{createWriteStream as x}from"node:fs";import{open as v}from"node:fs/promises";import{stdout as F}from"node:process";function y(e,t,r){return e>t?e<=r?e:r:t}async function b(e,t,r,a=0){let u=(await e.stat()).size,s=Math.max(a,Math.floor(u/t)),i=Buffer.allocUnsafe(r),f=[],n=0;for(let o=s;o=0&&le.length&&(e=T(e,s+218)),e[0]+=218,e[u+0]=s,e[s+0]=e[1]),u=s}return[e,u]}function d(e=0,t=655360){t=Math.max(219,t);let r=new Int32Array(new SharedArrayBuffer(t<<2));return r[0]=219,r[1]=e,r}function T(e,t=0){let r=e[0];t=Math.max(t,Math.ceil(r*1.618033988749895));let a=new Int32Array(new SharedArrayBuffer(t<<2));for(let u=0;ue[n].length&&(e[n]=T(e[n],D+2),u.push(n)),e[n][0]+=2,e[n][o+0]=D,e[n][D+0]=h,e[n][D+1]=m;else{let R=e[n][D+0];n!==R&&(D=e[n][D+1]),s.push([R,D,h,m])}}o+=1,l+=1}}s.splice(0,i)}while(s.length>0);return u}function O(e,t,r,a,u="",s){let i=new Array(t.length+1);i[0]=[r,3,0];let f=0,n=!1;do{let[o,I,l]=i[f];if(l>=216){--f;continue}i[f][1]+=1,++i[f][2];let c=e[o][I+0];if(c===0)continue;let M=e[o][c+0];o!==M&&(c=e[o][c+1],o=M),t[f]=l+32,i[++f]=[o,c+2,0];let m=e[o][c+1];m!==0&&(n&&a.write(u),n=!0,s(a,t,f,m))}while(f>=0)}import{Worker as B}from"node:worker_threads";function U(e){let t=new B(e);return t.on("error",r=>{throw r}),t.on("messageerror",r=>{throw r}),t.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${t.threadId} exited with code ${r}`)}),t}function g(e,t){return new Promise(r=>{e.once("message",r),e.postMessage(t)})}async function C(e,t,r,a=""){r=y(r,1,512);let u=await v(e,"r"),s=await b(u,r,107,16384);r=s.length;let i=new SharedArrayBuffer(1e4*r+1<<4),f=new Int16Array(i),n=new Int16Array(i,2),o=new Uint32Array(i,4),I=new Float64Array(i,8),l=new Array(r),c=[],M=new Array(r);for(let R=0;R{let E=_.id;for(l[_.id]=_.trie;c.length>0;){let X=await g(p,{type:1,a:E,b:c.pop(),counts:o,maxes:n,mins:f,sums:I,tries:l});for(let A of X.ids)l[A]=X.tries[A]}return c.push(E),p.terminate()})}await Promise.all(M),await u.close();let m=x(a,{fd:a.length<1?F.fd:void 0,flags:"a",highWaterMark:1048576}),h=Buffer.allocUnsafe(100);m.write("{"),O(l,h,c[0],m,", ",D),m.end(`} -`);function D(R,p,_,E){let X=Math.round(I[E<<1]/o[E<<2]);R.write(p.toString("utf8",0,_)),R.write("="),R.write((f[E<<3]/10).toFixed(1)),R.write("/"),R.write((X/10).toFixed(1)),R.write("/"),R.write((n[E<<3]/10).toFixed(1))}}import{open as Z}from"fs/promises";var P=11*48,q=111*48;function H(e,t,r){return e[t]===45?(++t,t+4>r?P-10*e[t]-e[t+2]:q-100*e[t]-10*e[t+1]-e[t+3]):t+4>r?10*e[t]+e[t+2]-P:100*e[t]+10*e[t+1]+e[t+3]-q}async function W({end:e,filePath:t,id:r,start:a,counts:u,maxes:s,mins:i,sums:f}){if(a>=e)return{id:r,trie:d(r,0)};let n=d(r),o=r*1e4+1,I=await Z(t,"r"),l=L(e-a),c=Buffer.allocUnsafe(l+107),M=0,m=0,h;for(;a=_?s[p]:_,++u[p>>1],f[p>>2]+=_}return await I.close(),{id:r,trie:n}}function k({a:e,b:t,tries:r,counts:a,maxes:u,mins:s,sums:i}){function f(o,I){o<<=3,I<<=3,s[o]=Math.min(s[o],s[I]),u[o]=Math.max(u[o],u[I]),a[o>>1]+=a[I>>1],i[o>>2]+=i[I>>2]}return{ids:S(r,e,t,f),tries:r}}if(K){let e=V(import.meta.url);C(process.argv[2],e,G())}else w.addListener("message",async e=>{if(e.type===0)w.postMessage(await W(e));else if(e.type===1)w.postMessage(k(e));else throw new Error("Unknown message type")}); +import{availableParallelism as Y}from"node:os";import{fileURLToPath as Q}from"node:url";import{isMainThread as $,parentPort as A}from"node:worker_threads";import{closeSync as Z,createWriteStream as F,openSync as G}from"node:fs";import{stdout as V}from"node:process";import{fstatSync as B,readSync as x}from"fs";function X(e,t,r){return e>t?e<=r?e:r:t}function w(e,t,r,c=0){let s=B(e).size,u=Math.max(c,Math.floor(s/t)),i=Buffer.allocUnsafe(r),f=[],n=0;for(let o=u;o=0&&le.length&&(e=T(e,u+218)),e[0]+=218,e[s+0]=u,e[u+0]=e[1]),s=u}return[e,s]}function b(e=0,t=655360){t=Math.max(219,t);let r=new Int32Array(new SharedArrayBuffer(t<<2));return r[0]=219,r[1]=e,r}function T(e,t=0){let r=e[0];t=Math.max(t,Math.ceil(r*1.618033988749895));let c=new Int32Array(new SharedArrayBuffer(t<<2));for(let s=0;se[n].length&&(e[n]=T(e[n],D+2),s.push(n)),e[n][0]+=2,e[n][o+0]=D,e[n][D+0]=h,e[n][D+1]=a;else{let R=e[n][D+0];n!==R&&(D=e[n][D+1]),u.push([R,D,h,a])}}o+=1,l+=1}}u.splice(0,i)}while(u.length>0);return s}function O(e,t,r,c,s="",u){let i=new Array(t.length+1);i[0]=[r,3,0];let f=0,n=!1;do{let[o,m,l]=i[f];if(l>=216){--f;continue}i[f][1]+=1,++i[f][2];let p=e[o][m+0];if(p===0)continue;let M=e[o][p+0];o!==M&&(p=e[o][p+1],o=M),t[f]=l+32,i[++f]=[o,p+2,0];let a=e[o][p+1];a!==0&&(n&&c.write(s),n=!0,u(c,t,f,a))}while(f>=0)}import{Worker as v}from"node:worker_threads";function U(e){let t=new v(e);return t.on("error",r=>{throw r}),t.on("messageerror",r=>{throw r}),t.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${t.threadId} exited with code ${r}`)}),t}function g(e,t){return new Promise(r=>{e.once("message",r),e.postMessage(t)})}async function C(e,t,r,c=""){r=X(r,1,512);let s=G(e,"r"),u=w(s,r,107,16384);r=u.length;let i=new SharedArrayBuffer(1e4*r+1<<4),f=new Int16Array(i),n=new Int16Array(i,2),o=new Uint32Array(i,4),m=new Float64Array(i,8),l=new Array(r),p=[],M=new Array(r);for(let R=0;R{let E=_.id;for(l[E]=_.trie;p.length>0;){let y=await g(I,{type:1,a:E,b:p.pop(),counts:o,maxes:n,mins:f,sums:m,tries:l});for(let d of y.ids)l[d]=y.tries[d]}return p.push(E),I.terminate()})}await Promise.all(M),Z(s);let a=F(c,{fd:c.length<1?V.fd:void 0,flags:"a",highWaterMark:1048576}),h=Buffer.allocUnsafe(100);a.write("{"),O(l,h,p[0],a,", ",D),a.end(`} +`);function D(R,I,_,E){let y=Math.round(m[E<<1]/o[E<<2]);R.write(I.toString("utf8",0,_)),R.write("="),R.write((f[E<<3]/10).toFixed(1)),R.write("/"),R.write((y/10).toFixed(1)),R.write("/"),R.write((n[E<<3]/10).toFixed(1))}}import{open as K}from"fs/promises";var P=11*48,q=111*48;function H(e,t,r){return e[t]===45?(++t,t+4>r?P-10*e[t]-e[t+2]:q-100*e[t]-10*e[t+1]-e[t+3]):t+4>r?10*e[t]+e[t+2]-P:100*e[t]+10*e[t+1]+e[t+3]-q}async function W({end:e,filePath:t,id:r,start:c,counts:s,maxes:u,mins:i,sums:f}){if(c>=e)return{id:r,trie:b(r,0)};let n=b(r),o=r*1e4+1,m=await K(t,"r"),l=L(e-c),p=Buffer.allocUnsafe(l+107),M=0,a=0,h;for(;c=_?u[I]:_,++s[I>>1],f[I>>2]+=_}return await m.close(),{id:r,trie:n}}function k({a:e,b:t,tries:r,counts:c,maxes:s,mins:u,sums:i}){function f(o,m){o<<=3,m<<=3,u[o]=Math.min(u[o],u[m]),s[o]=Math.max(s[o],s[m]),c[o>>1]+=c[m>>1],i[o>>2]+=i[m>>2]}return{ids:S(r,e,t,f),tries:r}}if($){let e=Q(import.meta.url);C(process.argv[2],e,Y())}else A.addListener("message",async e=>{if(e.type===0)A.postMessage(await W(e));else if(e.type===1)A.postMessage(k(e));else throw new Error("Unknown message type")}); //# sourceMappingURL=index.mjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index 2541ceb..742c3dd 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../src/index.ts", "../src/main.ts", "../src/utils/stream.ts", "../src/utils/utf8Trie.ts", "../src/utils/worker.ts", "../src/worker.ts", "../src/utils/parse.ts"], - "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport { RequestType, type Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === RequestType.PROCESS) {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === RequestType.MERGE) {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { WriteStream, createWriteStream } from \"node:fs\";\nimport { open } from \"node:fs/promises\";\nimport { stdout } from \"node:process\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\nimport { RequestType } from \"./types/request\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Open the given file\n const file = await open(filePath, \"r\");\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = await getFileChunks(\n file,\n maxWorkers,\n BRC.MAX_ENTRY_LEN,\n Config.HIGH_WATER_MARK_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: RequestType.PROCESS,\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[res.id] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: RequestType.MERGE,\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Close the file\n await file.close();\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? stdout.fd : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { FileHandle } from \"fs/promises\";\n\nimport { Config } from \"../constants/config\";\nimport { CharCode } from \"../constants/utf8\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport async function getFileChunks(\n file: FileHandle,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): Promise<[number, number][]> {\n // Get the file's size\n const size = (await file.stat()).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const res = await file.read(buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CharCode.NEWLINE);\n // If found\n if (newline >= 0 && newline < res.bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= Config.HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, Config.HIGH_WATER_MARK_MIN, Config.HIGH_WATER_MARK_MAX);\n}\n", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown: number[] = [];\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.push(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return grown;\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"node:worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { open } from \"fs/promises\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * BRC.MAX_STATIONS + 1;\n\n const file = await open(filePath, \"r\");\n const chunkSize = getHighWaterMark(end - start);\n const chunk = Buffer.allocUnsafe(chunkSize + BRC.MAX_ENTRY_LEN);\n\n // For each chunk\n let i = 0;\n let minI = 0;\n let leaf: number;\n while (start < end) {\n const res = await file.read(chunk, i, chunkSize, start);\n start += res.bytesRead;\n\n for (const N = i + res.bytesRead; i < N; ++i) {\n // If newline\n if (chunk[i] === CharCode.NEWLINE) {\n // Get semicolon\n let semI = i - 5;\n if (chunk[semI] !== CharCode.SEMICOLON) {\n semI += 1 | (1 + ~(chunk[semI - 1] === CharCode.SEMICOLON));\n }\n\n // Get temperature\n const tempV = parseDouble(chunk, semI + 1, i);\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, chunk, minI, semI);\n minI = i + 1;\n\n // If the station existed\n if (trie[leaf + TrieNodeProto.VALUE_IDX] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf + TrieNodeProto.VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TrieNodeProto.VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n chunk.copyWithin(0, minI, i);\n i -= minI;\n minI = 0;\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n await file.close();\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], - "mappings": "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", - "names": ["availableParallelism", "fileURLToPath", "isMainThread", "parentPort", "createWriteStream", "open", "stdout", "clamp", "value", "min", "max", "getFileChunks", "file", "target", "maxLineLength", "minSize", "size", "chunkSize", "buffer", "chunks", "start", "end", "res", "newline", "getHighWaterMark", "add", "trie", "key", "min", "max", "index", "child", "grow", "createTrie", "id", "size", "trie", "grow", "minSize", "length", "next", "i", "mergeLeft", "tries", "at", "bt", "mergeFn", "grown", "queue", "Q", "q", "ai", "bi", "bvi", "avi", "bn", "ri", "rt", "li", "lt", "print", "key", "trieIndex", "stream", "separator", "callbackFn", "stack", "top", "tail", "trieI", "childPtr", "numChild", "childI", "childTrieI", "valueIndex", "Worker", "createWorker", "workerPath", "worker", "err", "code", "exec", "req", "resolve", "run", "filePath", "workerPath", "maxWorkers", "outPath", "clamp", "file", "open", "chunks", "getFileChunks", "valBuf", "mins", "maxes", "counts", "sums", "tries", "unmerged", "tasks", "i", "worker", "createWorker", "exec", "res", "a", "id", "out", "createWriteStream", "stdout", "buffer", "print", "printStation", "stream", "name", "nameLen", "vi", "avg", "open", "CHAR_ZERO_11", "CHAR_ZERO_111", "parseDouble", "b", "min", "max", "run", "end", "filePath", "id", "start", "counts", "maxes", "mins", "sums", "createTrie", "trie", "stations", "file", "open", "chunkSize", "getHighWaterMark", "chunk", "i", "minI", "leaf", "res", "N", "semI", "tempV", "parseDouble", "add", "updateStation", "newStation", "index", "temp", "merge", "a", "b", "tries", "mergeStations", "ai", "bi", "mergeLeft", "isMainThread", "workerPath", "fileURLToPath", "run", "availableParallelism", "parentPort", "msg", "merge"] + "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport { RequestType, type Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === RequestType.PROCESS) {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === RequestType.MERGE) {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { closeSync, createWriteStream, openSync, WriteStream } from \"node:fs\";\nimport { stdout } from \"node:process\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\nimport { RequestType } from \"./types/request\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Open the given file\n const fd = openSync(filePath, \"r\");\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = getFileChunks(\n fd,\n maxWorkers,\n BRC.MAX_ENTRY_LEN,\n Config.HIGH_WATER_MARK_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: RequestType.PROCESS,\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[a] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: RequestType.MERGE,\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Close the file\n closeSync(fd);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? stdout.fd : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { fstatSync, readSync } from \"fs\";\nimport { Config } from \"../constants/config\";\nimport { CharCode } from \"../constants/utf8\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport function getFileChunks(\n fd: number,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): [number, number][] {\n // Get the file's size\n const size = fstatSync(fd).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const bytesRead = readSync(fd, buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CharCode.NEWLINE);\n // If found\n if (newline >= 0 && newline < bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= Config.HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, Config.HIGH_WATER_MARK_MIN, Config.HIGH_WATER_MARK_MAX);\n}\n", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown: number[] = [];\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.push(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return grown;\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"node:worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { open } from \"fs/promises\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * BRC.MAX_STATIONS + 1;\n\n const file = await open(filePath, \"r\");\n const chunkSize = getHighWaterMark(end - start);\n const chunk = Buffer.allocUnsafe(chunkSize + BRC.MAX_ENTRY_LEN);\n\n // For each chunk\n let i = 0;\n let minI = 0;\n let leaf: number;\n while (start < end) {\n const res = await file.read(chunk, i, chunkSize, start);\n start += res.bytesRead;\n\n for (const N = i + res.bytesRead; i < N; ++i) {\n // If newline\n if (chunk[i] === CharCode.NEWLINE) {\n // Get semicolon\n let semI = i - 5;\n if (chunk[semI] !== CharCode.SEMICOLON) {\n semI += 1 | (1 + ~(chunk[semI - 1] === CharCode.SEMICOLON));\n }\n\n // Get temperature\n const tempV = parseDouble(chunk, semI + 1, i);\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, chunk, minI, semI);\n minI = i + 1;\n\n // If the station existed\n if (trie[leaf + TrieNodeProto.VALUE_IDX] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf + TrieNodeProto.VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TrieNodeProto.VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n chunk.copyWithin(0, minI, i);\n i -= minI;\n minI = 0;\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n await file.close();\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], + "mappings": "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", + "names": ["availableParallelism", "fileURLToPath", "isMainThread", "parentPort", "closeSync", "createWriteStream", "openSync", "stdout", "fstatSync", "readSync", "clamp", "value", "min", "max", "getFileChunks", "fd", "target", "maxLineLength", "minSize", "size", "fstatSync", "chunkSize", "buffer", "chunks", "start", "end", "bytesRead", "readSync", "newline", "getHighWaterMark", "add", "trie", "key", "min", "max", "index", "child", "grow", "createTrie", "id", "size", "trie", "grow", "minSize", "length", "next", "i", "mergeLeft", "tries", "at", "bt", "mergeFn", "grown", "queue", "Q", "q", "ai", "bi", "bvi", "avi", "bn", "ri", "rt", "li", "lt", "print", "key", "trieIndex", "stream", "separator", "callbackFn", "stack", "top", "tail", "trieI", "childPtr", "numChild", "childI", "childTrieI", "valueIndex", "Worker", "createWorker", "workerPath", "worker", "err", "code", "exec", "req", "resolve", "run", "filePath", "workerPath", "maxWorkers", "outPath", "clamp", "fd", "openSync", "chunks", "getFileChunks", "valBuf", "mins", "maxes", "counts", "sums", "tries", "unmerged", "tasks", "i", "worker", "createWorker", "exec", "res", "a", "id", "closeSync", "out", "createWriteStream", "stdout", "buffer", "print", "printStation", "stream", "name", "nameLen", "vi", "avg", "open", "CHAR_ZERO_11", "CHAR_ZERO_111", "parseDouble", "b", "min", "max", "run", "end", "filePath", "id", "start", "counts", "maxes", "mins", "sums", "createTrie", "trie", "stations", "file", "open", "chunkSize", "getHighWaterMark", "chunk", "i", "minI", "leaf", "res", "N", "semI", "tempV", "parseDouble", "add", "updateStation", "newStation", "index", "temp", "merge", "a", "b", "tries", "mergeStations", "ai", "bi", "mergeLeft", "isMainThread", "workerPath", "fileURLToPath", "run", "availableParallelism", "parentPort", "msg", "merge"] } diff --git a/src/main/nodejs/havelessbemore/src/main.ts b/src/main/nodejs/havelessbemore/src/main.ts index 4cf6a7c..c1e86c1 100644 --- a/src/main/nodejs/havelessbemore/src/main.ts +++ b/src/main/nodejs/havelessbemore/src/main.ts @@ -1,5 +1,4 @@ -import { WriteStream, createWriteStream } from "node:fs"; -import { open } from "node:fs/promises"; +import { closeSync, createWriteStream, openSync, WriteStream } from "node:fs"; import { stdout } from "node:process"; import type { MergeRequest } from "./types/mergeRequest"; @@ -24,11 +23,11 @@ export async function run( maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX); // Open the given file - const file = await open(filePath, "r"); + const fd = openSync(filePath, "r"); // Split the file into chunks. Creates 1 or fewer chunks per worker - const chunks = await getFileChunks( - file, + const chunks = getFileChunks( + fd, maxWorkers, BRC.MAX_ENTRY_LEN, Config.HIGH_WATER_MARK_MIN, @@ -67,7 +66,7 @@ export async function run( }).then(async (res) => { // Add result to trie array const a = res.id; - tries[res.id] = res.trie; + tries[a] = res.trie; // Merge with other tries while (unmerged.length > 0) { const res = await exec(worker, { @@ -95,7 +94,7 @@ export async function run( await Promise.all(tasks); // Close the file - await file.close(); + closeSync(fd); // Print results const out = createWriteStream(outPath, { diff --git a/src/main/nodejs/havelessbemore/src/utils/stream.ts b/src/main/nodejs/havelessbemore/src/utils/stream.ts index 6bb3565..00ea135 100644 --- a/src/main/nodejs/havelessbemore/src/utils/stream.ts +++ b/src/main/nodejs/havelessbemore/src/utils/stream.ts @@ -1,5 +1,4 @@ -import { FileHandle } from "fs/promises"; - +import { fstatSync, readSync } from "fs"; import { Config } from "../constants/config"; import { CharCode } from "../constants/utf8"; @@ -34,14 +33,14 @@ export function clamp(value: number, min: number, max: number): number { * * @throws Will throw an error if the file cannot be opened or read. */ -export async function getFileChunks( - file: FileHandle, +export function getFileChunks( + fd: number, target: number, maxLineLength: number, minSize = 0, -): Promise<[number, number][]> { +): [number, number][] { // Get the file's size - const size = (await file.stat()).size; + const size = fstatSync(fd).size; // Calculate each chunk's target size const chunkSize = Math.max(minSize, Math.floor(size / target)); // Initialize constants @@ -51,11 +50,11 @@ export async function getFileChunks( let start = 0; for (let end = chunkSize; end < size; end += chunkSize) { // Read a line at the intended end index - const res = await file.read(buffer, 0, maxLineLength, end); + const bytesRead = readSync(fd, buffer, 0, maxLineLength, end); // Find the nearest newline ('\n') character const newline = buffer.indexOf(CharCode.NEWLINE); // If found - if (newline >= 0 && newline < res.bytesRead) { + if (newline >= 0 && newline < bytesRead) { // Align end with the newline end += newline + 1; // Add the chunk From de752852d07d11c07ef55a3951abef1ffd8c3e86 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Mon, 27 May 2024 00:40:53 -0400 Subject: [PATCH 59/69] Make worker process() function synchronous to avoid async overhead --- src/main/nodejs/havelessbemore/dist/index.mjs | 4 +- .../nodejs/havelessbemore/dist/index.mjs.map | 6 +- src/main/nodejs/havelessbemore/src/index.ts | 4 +- src/main/nodejs/havelessbemore/src/main.ts | 2 +- .../src/types/processRequest.ts | 2 +- src/main/nodejs/havelessbemore/src/worker.ts | 69 ++++++++++--------- 6 files changed, 47 insertions(+), 40 deletions(-) diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index a9541aa..bbc9dbd 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -1,3 +1,3 @@ -import{availableParallelism as Y}from"node:os";import{fileURLToPath as Q}from"node:url";import{isMainThread as $,parentPort as A}from"node:worker_threads";import{closeSync as Z,createWriteStream as F,openSync as G}from"node:fs";import{stdout as V}from"node:process";import{fstatSync as B,readSync as x}from"fs";function X(e,t,r){return e>t?e<=r?e:r:t}function w(e,t,r,c=0){let s=B(e).size,u=Math.max(c,Math.floor(s/t)),i=Buffer.allocUnsafe(r),f=[],n=0;for(let o=u;o=0&&le.length&&(e=T(e,u+218)),e[0]+=218,e[s+0]=u,e[u+0]=e[1]),s=u}return[e,s]}function b(e=0,t=655360){t=Math.max(219,t);let r=new Int32Array(new SharedArrayBuffer(t<<2));return r[0]=219,r[1]=e,r}function T(e,t=0){let r=e[0];t=Math.max(t,Math.ceil(r*1.618033988749895));let c=new Int32Array(new SharedArrayBuffer(t<<2));for(let s=0;se[n].length&&(e[n]=T(e[n],D+2),s.push(n)),e[n][0]+=2,e[n][o+0]=D,e[n][D+0]=h,e[n][D+1]=a;else{let R=e[n][D+0];n!==R&&(D=e[n][D+1]),u.push([R,D,h,a])}}o+=1,l+=1}}u.splice(0,i)}while(u.length>0);return s}function O(e,t,r,c,s="",u){let i=new Array(t.length+1);i[0]=[r,3,0];let f=0,n=!1;do{let[o,m,l]=i[f];if(l>=216){--f;continue}i[f][1]+=1,++i[f][2];let p=e[o][m+0];if(p===0)continue;let M=e[o][p+0];o!==M&&(p=e[o][p+1],o=M),t[f]=l+32,i[++f]=[o,p+2,0];let a=e[o][p+1];a!==0&&(n&&c.write(s),n=!0,u(c,t,f,a))}while(f>=0)}import{Worker as v}from"node:worker_threads";function U(e){let t=new v(e);return t.on("error",r=>{throw r}),t.on("messageerror",r=>{throw r}),t.on("exit",r=>{if(r>1||r<0)throw new Error(`Worker ${t.threadId} exited with code ${r}`)}),t}function g(e,t){return new Promise(r=>{e.once("message",r),e.postMessage(t)})}async function C(e,t,r,c=""){r=X(r,1,512);let s=G(e,"r"),u=w(s,r,107,16384);r=u.length;let i=new SharedArrayBuffer(1e4*r+1<<4),f=new Int16Array(i),n=new Int16Array(i,2),o=new Uint32Array(i,4),m=new Float64Array(i,8),l=new Array(r),p=[],M=new Array(r);for(let R=0;R{let E=_.id;for(l[E]=_.trie;p.length>0;){let y=await g(I,{type:1,a:E,b:p.pop(),counts:o,maxes:n,mins:f,sums:m,tries:l});for(let d of y.ids)l[d]=y.tries[d]}return p.push(E),I.terminate()})}await Promise.all(M),Z(s);let a=F(c,{fd:c.length<1?V.fd:void 0,flags:"a",highWaterMark:1048576}),h=Buffer.allocUnsafe(100);a.write("{"),O(l,h,p[0],a,", ",D),a.end(`} -`);function D(R,I,_,E){let y=Math.round(m[E<<1]/o[E<<2]);R.write(I.toString("utf8",0,_)),R.write("="),R.write((f[E<<3]/10).toFixed(1)),R.write("/"),R.write((y/10).toFixed(1)),R.write("/"),R.write((n[E<<3]/10).toFixed(1))}}import{open as K}from"fs/promises";var P=11*48,q=111*48;function H(e,t,r){return e[t]===45?(++t,t+4>r?P-10*e[t]-e[t+2]:q-100*e[t]-10*e[t+1]-e[t+3]):t+4>r?10*e[t]+e[t+2]-P:100*e[t]+10*e[t+1]+e[t+3]-q}async function W({end:e,filePath:t,id:r,start:c,counts:s,maxes:u,mins:i,sums:f}){if(c>=e)return{id:r,trie:b(r,0)};let n=b(r),o=r*1e4+1,m=await K(t,"r"),l=L(e-c),p=Buffer.allocUnsafe(l+107),M=0,a=0,h;for(;c=_?u[I]:_,++s[I>>1],f[I>>2]+=_}return await m.close(),{id:r,trie:n}}function k({a:e,b:t,tries:r,counts:c,maxes:s,mins:u,sums:i}){function f(o,m){o<<=3,m<<=3,u[o]=Math.min(u[o],u[m]),s[o]=Math.max(s[o],s[m]),c[o>>1]+=c[m>>1],i[o>>2]+=i[m>>2]}return{ids:S(r,e,t,f),tries:r}}if($){let e=Q(import.meta.url);C(process.argv[2],e,Y())}else A.addListener("message",async e=>{if(e.type===0)A.postMessage(await W(e));else if(e.type===1)A.postMessage(k(e));else throw new Error("Unknown message type")}); +import{availableParallelism as Y}from"node:os";import{fileURLToPath as Q}from"node:url";import{isMainThread as $,parentPort as g}from"node:worker_threads";import{closeSync as Z,createWriteStream as F,openSync as G}from"node:fs";import{stdout as K}from"node:process";import{fstatSync as B,readSync as x}from"fs";function X(e,r,t){return e>r?e<=t?e:t:r}function A(e,r,t,a=0){let u=B(e).size,s=Math.max(a,Math.floor(u/r)),p=Buffer.allocUnsafe(t),i=[],f=0;for(let o=s;o=0&&Ie.length&&(e=S(e,s+218)),e[0]+=218,e[u+0]=s,e[s+0]=e[1]),u=s}return[e,u]}function N(e=0,r=655360){r=Math.max(219,r);let t=new Int32Array(new SharedArrayBuffer(r<<2));return t[0]=219,t[1]=e,t}function S(e,r=0){let t=e[0];r=Math.max(r,Math.ceil(t*1.618033988749895));let a=new Int32Array(new SharedArrayBuffer(r<<2));for(let u=0;ue[f].length&&(e[f]=S(e[f],M+2),u.push(f)),e[f][0]+=2,e[f][o+0]=M,e[f][M+0]=h,e[f][M+1]=m;else{let n=e[f][M+0];f!==n&&(M=e[f][M+1]),s.push([n,M,h,m])}}o+=1,I+=1}}s.splice(0,p)}while(s.length>0);return u}function O(e,r,t,a,u="",s){let p=new Array(r.length+1);p[0]=[t,3,0];let i=0,f=!1;do{let[o,c,I]=p[i];if(I>=216){--i;continue}p[i][1]+=1,++p[i][2];let l=e[o][c+0];if(l===0)continue;let D=e[o][l+0];o!==D&&(l=e[o][l+1],o=D),r[i]=I+32,p[++i]=[o,l+2,0];let m=e[o][l+1];m!==0&&(f&&a.write(u),f=!0,s(a,r,i,m))}while(i>=0)}import{Worker as v}from"node:worker_threads";function C(e){let r=new v(e);return r.on("error",t=>{throw t}),r.on("messageerror",t=>{throw t}),r.on("exit",t=>{if(t>1||t<0)throw new Error(`Worker ${r.threadId} exited with code ${t}`)}),r}function d(e,r){return new Promise(t=>{e.once("message",t),e.postMessage(r)})}async function P(e,r,t,a=""){t=X(t,1,512);let u=G(e,"r"),s=A(u,t,107,16384);t=s.length;let p=new SharedArrayBuffer(1e4*t+1<<4),i=new Int16Array(p),f=new Int16Array(p,2),o=new Uint32Array(p,4),c=new Float64Array(p,8),I=new Array(t),l=[],D=new Array(t);for(let n=0;n{let _=E.id;for(I[_]=E.trie;l.length>0;){let y=await d(R,{type:1,a:_,b:l.pop(),counts:o,maxes:f,mins:i,sums:c,tries:I});for(let b of y.ids)I[b]=y.tries[b]}return l.push(_),R.terminate()})}await Promise.all(D),Z(u);let m=F(a,{fd:a.length<1?K.fd:void 0,flags:"a",highWaterMark:1048576}),h=Buffer.allocUnsafe(100);m.write("{"),O(I,h,l[0],m,", ",M),m.end(`} +`);function M(n,R,E,_){let y=Math.round(c[_<<1]/o[_<<2]);n.write(R.toString("utf8",0,E)),n.write("="),n.write((i[_<<3]/10).toFixed(1)),n.write("/"),n.write((y/10).toFixed(1)),n.write("/"),n.write((f[_<<3]/10).toFixed(1))}}import{readSync as V}from"fs";var U=11*48,q=111*48;function H(e,r,t){return e[r]===45?(++r,r+4>t?U-10*e[r]-e[r+2]:q-100*e[r]-10*e[r+1]-e[r+3]):r+4>t?10*e[r]+e[r+2]-U:100*e[r]+10*e[r+1]+e[r+3]-q}function W({end:e,fd:r,id:t,start:a,counts:u,maxes:s,mins:p,sums:i}){let f=w(e-a),o=Buffer.allocUnsafe(f+107),c=0,I=0,l=0,D=t*1e4+1,m=N(t);for(;a=R?s[n]:R,++u[n>>1],i[n>>2]+=R}return{id:t,trie:m}}function k({a:e,b:r,tries:t,counts:a,maxes:u,mins:s,sums:p}){function i(o,c){o<<=3,c<<=3,s[o]=Math.min(s[o],s[c]),u[o]=Math.max(u[o],u[c]),a[o>>1]+=a[c>>1],p[o>>2]+=p[c>>2]}return{ids:T(t,e,r,i),tries:t}}if($){let e=Q(import.meta.url);P(process.argv[2],e,Y())}else g.addListener("message",e=>{if(e.type===0)g.postMessage(W(e));else if(e.type===1)g.postMessage(k(e));else throw new Error("Unknown message type")}); //# sourceMappingURL=index.mjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index 742c3dd..cdc89d0 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../src/index.ts", "../src/main.ts", "../src/utils/stream.ts", "../src/utils/utf8Trie.ts", "../src/utils/worker.ts", "../src/worker.ts", "../src/utils/parse.ts"], - "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport { RequestType, type Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", async (msg: Request) => {\n if (msg.type === RequestType.PROCESS) {\n parentPort!.postMessage(await runWorker(msg as ProcessRequest));\n } else if (msg.type === RequestType.MERGE) {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { closeSync, createWriteStream, openSync, WriteStream } from \"node:fs\";\nimport { stdout } from \"node:process\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\nimport { RequestType } from \"./types/request\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Open the given file\n const fd = openSync(filePath, \"r\");\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = getFileChunks(\n fd,\n maxWorkers,\n BRC.MAX_ENTRY_LEN,\n Config.HIGH_WATER_MARK_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: RequestType.PROCESS,\n counts,\n end: chunks[i][1],\n filePath,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[a] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: RequestType.MERGE,\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Close the file\n closeSync(fd);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? stdout.fd : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { fstatSync, readSync } from \"fs\";\nimport { Config } from \"../constants/config\";\nimport { CharCode } from \"../constants/utf8\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport function getFileChunks(\n fd: number,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): [number, number][] {\n // Get the file's size\n const size = fstatSync(fd).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const bytesRead = readSync(fd, buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CharCode.NEWLINE);\n // If found\n if (newline >= 0 && newline < bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= Config.HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, Config.HIGH_WATER_MARK_MIN, Config.HIGH_WATER_MARK_MAX);\n}\n", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown: number[] = [];\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.push(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return grown;\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"node:worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { open } from \"fs/promises\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\n\nexport async function run({\n end,\n filePath,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): Promise {\n // Check chunk size\n if (start >= end) {\n return { id, trie: createTrie(id, 0) };\n }\n\n // Initialize constants\n let trie = createTrie(id);\n let stations = id * BRC.MAX_STATIONS + 1;\n\n const file = await open(filePath, \"r\");\n const chunkSize = getHighWaterMark(end - start);\n const chunk = Buffer.allocUnsafe(chunkSize + BRC.MAX_ENTRY_LEN);\n\n // For each chunk\n let i = 0;\n let minI = 0;\n let leaf: number;\n while (start < end) {\n const res = await file.read(chunk, i, chunkSize, start);\n start += res.bytesRead;\n\n for (const N = i + res.bytesRead; i < N; ++i) {\n // If newline\n if (chunk[i] === CharCode.NEWLINE) {\n // Get semicolon\n let semI = i - 5;\n if (chunk[semI] !== CharCode.SEMICOLON) {\n semI += 1 | (1 + ~(chunk[semI - 1] === CharCode.SEMICOLON));\n }\n\n // Get temperature\n const tempV = parseDouble(chunk, semI + 1, i);\n\n // Add the station's name to the trie and get leaf index\n [trie, leaf] = add(trie, chunk, minI, semI);\n minI = i + 1;\n\n // If the station existed\n if (trie[leaf + TrieNodeProto.VALUE_IDX] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf + TrieNodeProto.VALUE_IDX], tempV);\n } else {\n // Add the new station's value\n trie[leaf + TrieNodeProto.VALUE_IDX] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n chunk.copyWithin(0, minI, i);\n i -= minI;\n minI = 0;\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n await file.close();\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], - "mappings": "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", - "names": ["availableParallelism", "fileURLToPath", "isMainThread", "parentPort", "closeSync", "createWriteStream", "openSync", "stdout", "fstatSync", "readSync", "clamp", "value", "min", "max", "getFileChunks", "fd", "target", "maxLineLength", "minSize", "size", "fstatSync", "chunkSize", "buffer", "chunks", "start", "end", "bytesRead", "readSync", "newline", "getHighWaterMark", "add", "trie", "key", "min", "max", "index", "child", "grow", "createTrie", "id", "size", "trie", "grow", "minSize", "length", "next", "i", "mergeLeft", "tries", "at", "bt", "mergeFn", "grown", "queue", "Q", "q", "ai", "bi", "bvi", "avi", "bn", "ri", "rt", "li", "lt", "print", "key", "trieIndex", "stream", "separator", "callbackFn", "stack", "top", "tail", "trieI", "childPtr", "numChild", "childI", "childTrieI", "valueIndex", "Worker", "createWorker", "workerPath", "worker", "err", "code", "exec", "req", "resolve", "run", "filePath", "workerPath", "maxWorkers", "outPath", "clamp", "fd", "openSync", "chunks", "getFileChunks", "valBuf", "mins", "maxes", "counts", "sums", "tries", "unmerged", "tasks", "i", "worker", "createWorker", "exec", "res", "a", "id", "closeSync", "out", "createWriteStream", "stdout", "buffer", "print", "printStation", "stream", "name", "nameLen", "vi", "avg", "open", "CHAR_ZERO_11", "CHAR_ZERO_111", "parseDouble", "b", "min", "max", "run", "end", "filePath", "id", "start", "counts", "maxes", "mins", "sums", "createTrie", "trie", "stations", "file", "open", "chunkSize", "getHighWaterMark", "chunk", "i", "minI", "leaf", "res", "N", "semI", "tempV", "parseDouble", "add", "updateStation", "newStation", "index", "temp", "merge", "a", "b", "tries", "mergeStations", "ai", "bi", "mergeLeft", "isMainThread", "workerPath", "fileURLToPath", "run", "availableParallelism", "parentPort", "msg", "merge"] + "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport { RequestType, type Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", (msg: Request) => {\n if (msg.type === RequestType.PROCESS) {\n parentPort!.postMessage(runWorker(msg as ProcessRequest));\n } else if (msg.type === RequestType.MERGE) {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { closeSync, createWriteStream, openSync, WriteStream } from \"node:fs\";\nimport { stdout } from \"node:process\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\nimport { RequestType } from \"./types/request\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Open the given file\n const fd = openSync(filePath, \"r\");\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = getFileChunks(\n fd,\n maxWorkers,\n BRC.MAX_ENTRY_LEN,\n Config.HIGH_WATER_MARK_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: RequestType.PROCESS,\n counts,\n end: chunks[i][1],\n fd,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[a] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: RequestType.MERGE,\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Close the file\n closeSync(fd);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? stdout.fd : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { fstatSync, readSync } from \"fs\";\nimport { Config } from \"../constants/config\";\nimport { CharCode } from \"../constants/utf8\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport function getFileChunks(\n fd: number,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): [number, number][] {\n // Get the file's size\n const size = fstatSync(fd).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const bytesRead = readSync(fd, buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CharCode.NEWLINE);\n // If found\n if (newline >= 0 && newline < bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= Config.HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, Config.HIGH_WATER_MARK_MIN, Config.HIGH_WATER_MARK_MAX);\n}\n", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown: number[] = [];\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.push(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return grown;\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"node:worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { readSync } from \"fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\n\nexport function run({\n end,\n fd,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): ProcessResponse {\n\n // Initialize constants\n const chunkSize = getHighWaterMark(end - start);\n const chunk = Buffer.allocUnsafe(chunkSize + BRC.MAX_ENTRY_LEN);\n\n // Initialize variables\n let bufI = 0;\n let leaf = 0;\n let minI = 0;\n let stations = id * BRC.MAX_STATIONS + 1;\n let trie = createTrie(id);\n\n // For each chunk\n while (start < end) {\n\n // Read the chunk into memory\n const bytesRead = readSync(fd, chunk, bufI, chunkSize, start);\n start += bytesRead;\n\n // For each byte\n for (const N = bufI + bytesRead; bufI < N; ++bufI) {\n\n // If newline\n if (chunk[bufI] === CharCode.NEWLINE) {\n\n // Get semicolon\n let semI = bufI - 5;\n if (chunk[semI] !== CharCode.SEMICOLON) {\n semI += 1 | (1 + ~(chunk[semI - 1] === CharCode.SEMICOLON));\n }\n\n // Add the station's name to the trie and get leaf\n [trie, leaf] = add(trie, chunk, minI, semI);\n\n // Update next entry's min\n minI = bufI + 1;\n\n // Get temperature\n const tempV = parseDouble(chunk, semI + 1, bufI);\n\n // If the station existed\n leaf += TrieNodeProto.VALUE_IDX;\n if (trie[leaf] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf], tempV);\n } else {\n // Add the new station's value\n trie[leaf] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n // Prepend any incomplete entry to the next chunk\n chunk.copyWithin(0, minI, bufI);\n\n // Update indices for the next chunk\n bufI -= minI;\n minI = 0;\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], + "mappings": "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", + "names": ["availableParallelism", "fileURLToPath", "isMainThread", "parentPort", "closeSync", "createWriteStream", "openSync", "stdout", "fstatSync", "readSync", "clamp", "value", "min", "max", "getFileChunks", "fd", "target", "maxLineLength", "minSize", "size", "fstatSync", "chunkSize", "buffer", "chunks", "start", "end", "bytesRead", "readSync", "newline", "getHighWaterMark", "add", "trie", "key", "min", "max", "index", "child", "grow", "createTrie", "id", "size", "trie", "grow", "minSize", "length", "next", "i", "mergeLeft", "tries", "at", "bt", "mergeFn", "grown", "queue", "Q", "q", "ai", "bi", "bvi", "avi", "bn", "ri", "rt", "li", "lt", "print", "key", "trieIndex", "stream", "separator", "callbackFn", "stack", "top", "tail", "trieI", "childPtr", "numChild", "childI", "childTrieI", "valueIndex", "Worker", "createWorker", "workerPath", "worker", "err", "code", "exec", "req", "resolve", "run", "filePath", "workerPath", "maxWorkers", "outPath", "clamp", "fd", "openSync", "chunks", "getFileChunks", "valBuf", "mins", "maxes", "counts", "sums", "tries", "unmerged", "tasks", "i", "worker", "createWorker", "exec", "res", "a", "id", "closeSync", "out", "createWriteStream", "stdout", "buffer", "print", "printStation", "stream", "name", "nameLen", "vi", "avg", "readSync", "CHAR_ZERO_11", "CHAR_ZERO_111", "parseDouble", "b", "min", "max", "run", "end", "fd", "id", "start", "counts", "maxes", "mins", "sums", "chunkSize", "getHighWaterMark", "chunk", "bufI", "leaf", "minI", "stations", "trie", "createTrie", "bytesRead", "readSync", "N", "semI", "add", "tempV", "parseDouble", "updateStation", "newStation", "index", "temp", "merge", "a", "b", "tries", "mergeStations", "ai", "bi", "mergeLeft", "isMainThread", "workerPath", "fileURLToPath", "run", "availableParallelism", "parentPort", "msg", "merge"] } diff --git a/src/main/nodejs/havelessbemore/src/index.ts b/src/main/nodejs/havelessbemore/src/index.ts index 1dadc67..47891ad 100644 --- a/src/main/nodejs/havelessbemore/src/index.ts +++ b/src/main/nodejs/havelessbemore/src/index.ts @@ -13,9 +13,9 @@ if (isMainThread) { const workerPath = fileURLToPath(import.meta.url); runMain(process.argv[2], workerPath, availableParallelism()); } else { - parentPort!.addListener("message", async (msg: Request) => { + parentPort!.addListener("message", (msg: Request) => { if (msg.type === RequestType.PROCESS) { - parentPort!.postMessage(await runWorker(msg as ProcessRequest)); + parentPort!.postMessage(runWorker(msg as ProcessRequest)); } else if (msg.type === RequestType.MERGE) { parentPort!.postMessage(merge(msg as MergeRequest)); } else { diff --git a/src/main/nodejs/havelessbemore/src/main.ts b/src/main/nodejs/havelessbemore/src/main.ts index c1e86c1..004ebab 100644 --- a/src/main/nodejs/havelessbemore/src/main.ts +++ b/src/main/nodejs/havelessbemore/src/main.ts @@ -57,7 +57,7 @@ export async function run( type: RequestType.PROCESS, counts, end: chunks[i][1], - filePath, + fd, id: i, maxes, mins, diff --git a/src/main/nodejs/havelessbemore/src/types/processRequest.ts b/src/main/nodejs/havelessbemore/src/types/processRequest.ts index 06f566a..7936108 100644 --- a/src/main/nodejs/havelessbemore/src/types/processRequest.ts +++ b/src/main/nodejs/havelessbemore/src/types/processRequest.ts @@ -3,7 +3,7 @@ import { Request, RequestType } from "./request"; export interface ProcessRequest extends Request { type: RequestType.PROCESS; end: number; - filePath: string; + fd: number; id: number; start: number; // Shared memory diff --git a/src/main/nodejs/havelessbemore/src/worker.ts b/src/main/nodejs/havelessbemore/src/worker.ts index e7b27ab..b09aaa4 100644 --- a/src/main/nodejs/havelessbemore/src/worker.ts +++ b/src/main/nodejs/havelessbemore/src/worker.ts @@ -1,4 +1,4 @@ -import { open } from "fs/promises"; +import { readSync } from "fs"; import type { MergeRequest } from "./types/mergeRequest"; import type { MergeResponse } from "./types/mergeResponse"; @@ -11,9 +11,9 @@ import { parseDouble } from "./utils/parse"; import { getHighWaterMark } from "./utils/stream"; import { add, createTrie, mergeLeft } from "./utils/utf8Trie"; -export async function run({ +export function run({ end, - filePath, + fd, id, start, // Shared memory @@ -21,57 +21,65 @@ export async function run({ maxes, mins, sums, -}: ProcessRequest): Promise { - // Check chunk size - if (start >= end) { - return { id, trie: createTrie(id, 0) }; - } +}: ProcessRequest): ProcessResponse { // Initialize constants - let trie = createTrie(id); - let stations = id * BRC.MAX_STATIONS + 1; - - const file = await open(filePath, "r"); const chunkSize = getHighWaterMark(end - start); const chunk = Buffer.allocUnsafe(chunkSize + BRC.MAX_ENTRY_LEN); - // For each chunk - let i = 0; + // Initialize variables + let bufI = 0; + let leaf = 0; let minI = 0; - let leaf: number; + let stations = id * BRC.MAX_STATIONS + 1; + let trie = createTrie(id); + + // For each chunk while (start < end) { - const res = await file.read(chunk, i, chunkSize, start); - start += res.bytesRead; - for (const N = i + res.bytesRead; i < N; ++i) { + // Read the chunk into memory + const bytesRead = readSync(fd, chunk, bufI, chunkSize, start); + start += bytesRead; + + // For each byte + for (const N = bufI + bytesRead; bufI < N; ++bufI) { + // If newline - if (chunk[i] === CharCode.NEWLINE) { + if (chunk[bufI] === CharCode.NEWLINE) { + // Get semicolon - let semI = i - 5; + let semI = bufI - 5; if (chunk[semI] !== CharCode.SEMICOLON) { semI += 1 | (1 + ~(chunk[semI - 1] === CharCode.SEMICOLON)); } - // Get temperature - const tempV = parseDouble(chunk, semI + 1, i); - - // Add the station's name to the trie and get leaf index + // Add the station's name to the trie and get leaf [trie, leaf] = add(trie, chunk, minI, semI); - minI = i + 1; + + // Update next entry's min + minI = bufI + 1; + + // Get temperature + const tempV = parseDouble(chunk, semI + 1, bufI); // If the station existed - if (trie[leaf + TrieNodeProto.VALUE_IDX] !== Trie.NULL) { + leaf += TrieNodeProto.VALUE_IDX; + if (trie[leaf] !== Trie.NULL) { // Update the station's value - updateStation(trie[leaf + TrieNodeProto.VALUE_IDX], tempV); + updateStation(trie[leaf], tempV); } else { // Add the new station's value - trie[leaf + TrieNodeProto.VALUE_IDX] = stations; + trie[leaf] = stations; newStation(stations++, tempV); } } } - chunk.copyWithin(0, minI, i); - i -= minI; + + // Prepend any incomplete entry to the next chunk + chunk.copyWithin(0, minI, bufI); + + // Update indices for the next chunk + bufI -= minI; minI = 0; } @@ -90,7 +98,6 @@ export async function run({ sums[index >> 2] += temp; } - await file.close(); return { id, trie }; } From da6ba82e423fc38e1e3baafa3102ec871844b6f5 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Mon, 27 May 2024 00:46:27 -0400 Subject: [PATCH 60/69] Replace Math.max and Math.min with ternaries --- src/main/nodejs/havelessbemore/dist/index.mjs | 4 ++-- src/main/nodejs/havelessbemore/dist/index.mjs.map | 4 ++-- src/main/nodejs/havelessbemore/src/worker.ts | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index bbc9dbd..c8bc082 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -1,3 +1,3 @@ -import{availableParallelism as Y}from"node:os";import{fileURLToPath as Q}from"node:url";import{isMainThread as $,parentPort as g}from"node:worker_threads";import{closeSync as Z,createWriteStream as F,openSync as G}from"node:fs";import{stdout as K}from"node:process";import{fstatSync as B,readSync as x}from"fs";function X(e,r,t){return e>r?e<=t?e:t:r}function A(e,r,t,a=0){let u=B(e).size,s=Math.max(a,Math.floor(u/r)),p=Buffer.allocUnsafe(t),i=[],f=0;for(let o=s;o=0&&Ie.length&&(e=S(e,s+218)),e[0]+=218,e[u+0]=s,e[s+0]=e[1]),u=s}return[e,u]}function N(e=0,r=655360){r=Math.max(219,r);let t=new Int32Array(new SharedArrayBuffer(r<<2));return t[0]=219,t[1]=e,t}function S(e,r=0){let t=e[0];r=Math.max(r,Math.ceil(t*1.618033988749895));let a=new Int32Array(new SharedArrayBuffer(r<<2));for(let u=0;ue[f].length&&(e[f]=S(e[f],M+2),u.push(f)),e[f][0]+=2,e[f][o+0]=M,e[f][M+0]=h,e[f][M+1]=m;else{let n=e[f][M+0];f!==n&&(M=e[f][M+1]),s.push([n,M,h,m])}}o+=1,I+=1}}s.splice(0,p)}while(s.length>0);return u}function O(e,r,t,a,u="",s){let p=new Array(r.length+1);p[0]=[t,3,0];let i=0,f=!1;do{let[o,c,I]=p[i];if(I>=216){--i;continue}p[i][1]+=1,++p[i][2];let l=e[o][c+0];if(l===0)continue;let D=e[o][l+0];o!==D&&(l=e[o][l+1],o=D),r[i]=I+32,p[++i]=[o,l+2,0];let m=e[o][l+1];m!==0&&(f&&a.write(u),f=!0,s(a,r,i,m))}while(i>=0)}import{Worker as v}from"node:worker_threads";function C(e){let r=new v(e);return r.on("error",t=>{throw t}),r.on("messageerror",t=>{throw t}),r.on("exit",t=>{if(t>1||t<0)throw new Error(`Worker ${r.threadId} exited with code ${t}`)}),r}function d(e,r){return new Promise(t=>{e.once("message",t),e.postMessage(r)})}async function P(e,r,t,a=""){t=X(t,1,512);let u=G(e,"r"),s=A(u,t,107,16384);t=s.length;let p=new SharedArrayBuffer(1e4*t+1<<4),i=new Int16Array(p),f=new Int16Array(p,2),o=new Uint32Array(p,4),c=new Float64Array(p,8),I=new Array(t),l=[],D=new Array(t);for(let n=0;n{let _=E.id;for(I[_]=E.trie;l.length>0;){let y=await d(R,{type:1,a:_,b:l.pop(),counts:o,maxes:f,mins:i,sums:c,tries:I});for(let b of y.ids)I[b]=y.tries[b]}return l.push(_),R.terminate()})}await Promise.all(D),Z(u);let m=F(a,{fd:a.length<1?K.fd:void 0,flags:"a",highWaterMark:1048576}),h=Buffer.allocUnsafe(100);m.write("{"),O(I,h,l[0],m,", ",M),m.end(`} -`);function M(n,R,E,_){let y=Math.round(c[_<<1]/o[_<<2]);n.write(R.toString("utf8",0,E)),n.write("="),n.write((i[_<<3]/10).toFixed(1)),n.write("/"),n.write((y/10).toFixed(1)),n.write("/"),n.write((f[_<<3]/10).toFixed(1))}}import{readSync as V}from"fs";var U=11*48,q=111*48;function H(e,r,t){return e[r]===45?(++r,r+4>t?U-10*e[r]-e[r+2]:q-100*e[r]-10*e[r+1]-e[r+3]):r+4>t?10*e[r]+e[r+2]-U:100*e[r]+10*e[r+1]+e[r+3]-q}function W({end:e,fd:r,id:t,start:a,counts:u,maxes:s,mins:p,sums:i}){let f=w(e-a),o=Buffer.allocUnsafe(f+107),c=0,I=0,l=0,D=t*1e4+1,m=N(t);for(;a=R?s[n]:R,++u[n>>1],i[n>>2]+=R}return{id:t,trie:m}}function k({a:e,b:r,tries:t,counts:a,maxes:u,mins:s,sums:p}){function i(o,c){o<<=3,c<<=3,s[o]=Math.min(s[o],s[c]),u[o]=Math.max(u[o],u[c]),a[o>>1]+=a[c>>1],p[o>>2]+=p[c>>2]}return{ids:T(t,e,r,i),tries:t}}if($){let e=Q(import.meta.url);P(process.argv[2],e,Y())}else g.addListener("message",e=>{if(e.type===0)g.postMessage(W(e));else if(e.type===1)g.postMessage(k(e));else throw new Error("Unknown message type")}); +import{availableParallelism as Y}from"node:os";import{fileURLToPath as Q}from"node:url";import{isMainThread as $,parentPort as g}from"node:worker_threads";import{closeSync as x,createWriteStream as F,openSync as G}from"node:fs";import{stdout as K}from"node:process";import{fstatSync as B,readSync as v}from"fs";function X(e,r,t){return e>r?e<=t?e:t:r}function b(e,r,t,a=0){let u=B(e).size,s=Math.max(a,Math.floor(u/r)),I=Buffer.allocUnsafe(t),p=[],c=0;for(let o=s;o=0&&ie.length&&(e=S(e,s+218)),e[0]+=218,e[u+0]=s,e[s+0]=e[1]),u=s}return[e,u]}function N(e=0,r=655360){r=Math.max(219,r);let t=new Int32Array(new SharedArrayBuffer(r<<2));return t[0]=219,t[1]=e,t}function S(e,r=0){let t=e[0];r=Math.max(r,Math.ceil(t*1.618033988749895));let a=new Int32Array(new SharedArrayBuffer(r<<2));for(let u=0;ue[c].length&&(e[c]=S(e[c],M+2),u.push(c)),e[c][0]+=2,e[c][o+0]=M,e[c][M+0]=h,e[c][M+1]=m;else{let n=e[c][M+0];c!==n&&(M=e[c][M+1]),s.push([n,M,h,m])}}o+=1,i+=1}}s.splice(0,I)}while(s.length>0);return u}function O(e,r,t,a,u="",s){let I=new Array(r.length+1);I[0]=[t,3,0];let p=0,c=!1;do{let[o,f,i]=I[p];if(i>=216){--p;continue}I[p][1]+=1,++I[p][2];let l=e[o][f+0];if(l===0)continue;let D=e[o][l+0];o!==D&&(l=e[o][l+1],o=D),r[p]=i+32,I[++p]=[o,l+2,0];let m=e[o][l+1];m!==0&&(c&&a.write(u),c=!0,s(a,r,p,m))}while(p>=0)}import{Worker as Z}from"node:worker_threads";function C(e){let r=new Z(e);return r.on("error",t=>{throw t}),r.on("messageerror",t=>{throw t}),r.on("exit",t=>{if(t>1||t<0)throw new Error(`Worker ${r.threadId} exited with code ${t}`)}),r}function d(e,r){return new Promise(t=>{e.once("message",t),e.postMessage(r)})}async function P(e,r,t,a=""){t=X(t,1,512);let u=G(e,"r"),s=b(u,t,107,16384);t=s.length;let I=new SharedArrayBuffer(1e4*t+1<<4),p=new Int16Array(I),c=new Int16Array(I,2),o=new Uint32Array(I,4),f=new Float64Array(I,8),i=new Array(t),l=[],D=new Array(t);for(let n=0;n{let _=E.id;for(i[_]=E.trie;l.length>0;){let y=await d(R,{type:1,a:_,b:l.pop(),counts:o,maxes:c,mins:p,sums:f,tries:i});for(let A of y.ids)i[A]=y.tries[A]}return l.push(_),R.terminate()})}await Promise.all(D),x(u);let m=F(a,{fd:a.length<1?K.fd:void 0,flags:"a",highWaterMark:1048576}),h=Buffer.allocUnsafe(100);m.write("{"),O(i,h,l[0],m,", ",M),m.end(`} +`);function M(n,R,E,_){let y=Math.round(f[_<<1]/o[_<<2]);n.write(R.toString("utf8",0,E)),n.write("="),n.write((p[_<<3]/10).toFixed(1)),n.write("/"),n.write((y/10).toFixed(1)),n.write("/"),n.write((c[_<<3]/10).toFixed(1))}}import{readSync as V}from"fs";var U=11*48,q=111*48;function H(e,r,t){return e[r]===45?(++r,r+4>t?U-10*e[r]-e[r+2]:q-100*e[r]-10*e[r+1]-e[r+3]):r+4>t?10*e[r]+e[r+2]-U:100*e[r]+10*e[r+1]+e[r+3]-q}function W({end:e,fd:r,id:t,start:a,counts:u,maxes:s,mins:I,sums:p}){let c=w(e-a),o=Buffer.allocUnsafe(c+107),f=0,i=0,l=0,D=t*1e4+1,m=N(t);for(;a=R?s[n]:R,++u[n>>1],p[n>>2]+=R}return{id:t,trie:m}}function k({a:e,b:r,tries:t,counts:a,maxes:u,mins:s,sums:I}){function p(o,f){o<<=3,f<<=3,s[o]=s[o]<=s[f]?s[o]:s[f],u[o]=u[o]>=u[f]?u[o]:u[f],a[o>>1]+=a[f>>1],I[o>>2]+=I[f>>2]}return{ids:T(t,e,r,p),tries:t}}if($){let e=Q(import.meta.url);P(process.argv[2],e,Y())}else g.addListener("message",e=>{if(e.type===0)g.postMessage(W(e));else if(e.type===1)g.postMessage(k(e));else throw new Error("Unknown message type")}); //# sourceMappingURL=index.mjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index cdc89d0..3cdfd2f 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../src/index.ts", "../src/main.ts", "../src/utils/stream.ts", "../src/utils/utf8Trie.ts", "../src/utils/worker.ts", "../src/worker.ts", "../src/utils/parse.ts"], - "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport { RequestType, type Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", (msg: Request) => {\n if (msg.type === RequestType.PROCESS) {\n parentPort!.postMessage(runWorker(msg as ProcessRequest));\n } else if (msg.type === RequestType.MERGE) {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { closeSync, createWriteStream, openSync, WriteStream } from \"node:fs\";\nimport { stdout } from \"node:process\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\nimport { RequestType } from \"./types/request\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Open the given file\n const fd = openSync(filePath, \"r\");\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = getFileChunks(\n fd,\n maxWorkers,\n BRC.MAX_ENTRY_LEN,\n Config.HIGH_WATER_MARK_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: RequestType.PROCESS,\n counts,\n end: chunks[i][1],\n fd,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[a] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: RequestType.MERGE,\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Close the file\n closeSync(fd);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? stdout.fd : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { fstatSync, readSync } from \"fs\";\nimport { Config } from \"../constants/config\";\nimport { CharCode } from \"../constants/utf8\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport function getFileChunks(\n fd: number,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): [number, number][] {\n // Get the file's size\n const size = fstatSync(fd).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const bytesRead = readSync(fd, buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CharCode.NEWLINE);\n // If found\n if (newline >= 0 && newline < bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= Config.HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, Config.HIGH_WATER_MARK_MIN, Config.HIGH_WATER_MARK_MAX);\n}\n", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown: number[] = [];\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.push(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return grown;\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"node:worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { readSync } from \"fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\n\nexport function run({\n end,\n fd,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): ProcessResponse {\n\n // Initialize constants\n const chunkSize = getHighWaterMark(end - start);\n const chunk = Buffer.allocUnsafe(chunkSize + BRC.MAX_ENTRY_LEN);\n\n // Initialize variables\n let bufI = 0;\n let leaf = 0;\n let minI = 0;\n let stations = id * BRC.MAX_STATIONS + 1;\n let trie = createTrie(id);\n\n // For each chunk\n while (start < end) {\n\n // Read the chunk into memory\n const bytesRead = readSync(fd, chunk, bufI, chunkSize, start);\n start += bytesRead;\n\n // For each byte\n for (const N = bufI + bytesRead; bufI < N; ++bufI) {\n\n // If newline\n if (chunk[bufI] === CharCode.NEWLINE) {\n\n // Get semicolon\n let semI = bufI - 5;\n if (chunk[semI] !== CharCode.SEMICOLON) {\n semI += 1 | (1 + ~(chunk[semI - 1] === CharCode.SEMICOLON));\n }\n\n // Add the station's name to the trie and get leaf\n [trie, leaf] = add(trie, chunk, minI, semI);\n\n // Update next entry's min\n minI = bufI + 1;\n\n // Get temperature\n const tempV = parseDouble(chunk, semI + 1, bufI);\n\n // If the station existed\n leaf += TrieNodeProto.VALUE_IDX;\n if (trie[leaf] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf], tempV);\n } else {\n // Add the new station's value\n trie[leaf] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n // Prepend any incomplete entry to the next chunk\n chunk.copyWithin(0, minI, bufI);\n\n // Update indices for the next chunk\n bufI -= minI;\n minI = 0;\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = Math.min(mins[ai], mins[bi]);\n maxes[ai] = Math.max(maxes[ai], maxes[bi]);\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], - "mappings": "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", + "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport { RequestType, type Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", (msg: Request) => {\n if (msg.type === RequestType.PROCESS) {\n parentPort!.postMessage(runWorker(msg as ProcessRequest));\n } else if (msg.type === RequestType.MERGE) {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { closeSync, createWriteStream, openSync, WriteStream } from \"node:fs\";\nimport { stdout } from \"node:process\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\nimport { RequestType } from \"./types/request\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Open the given file\n const fd = openSync(filePath, \"r\");\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = getFileChunks(\n fd,\n maxWorkers,\n BRC.MAX_ENTRY_LEN,\n Config.HIGH_WATER_MARK_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: RequestType.PROCESS,\n counts,\n end: chunks[i][1],\n fd,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[a] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: RequestType.MERGE,\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Close the file\n closeSync(fd);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? stdout.fd : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { fstatSync, readSync } from \"fs\";\nimport { Config } from \"../constants/config\";\nimport { CharCode } from \"../constants/utf8\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport function getFileChunks(\n fd: number,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): [number, number][] {\n // Get the file's size\n const size = fstatSync(fd).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const bytesRead = readSync(fd, buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CharCode.NEWLINE);\n // If found\n if (newline >= 0 && newline < bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= Config.HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, Config.HIGH_WATER_MARK_MIN, Config.HIGH_WATER_MARK_MAX);\n}\n", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown: number[] = [];\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.push(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return grown;\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"node:worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { readSync } from \"fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\n\nexport function run({\n end,\n fd,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): ProcessResponse {\n\n // Initialize constants\n const chunkSize = getHighWaterMark(end - start);\n const chunk = Buffer.allocUnsafe(chunkSize + BRC.MAX_ENTRY_LEN);\n\n // Initialize variables\n let bufI = 0;\n let leaf = 0;\n let minI = 0;\n let stations = id * BRC.MAX_STATIONS + 1;\n let trie = createTrie(id);\n\n // For each chunk\n while (start < end) {\n\n // Read the chunk into memory\n const bytesRead = readSync(fd, chunk, bufI, chunkSize, start);\n start += bytesRead;\n\n // For each byte\n for (const N = bufI + bytesRead; bufI < N; ++bufI) {\n\n // If newline\n if (chunk[bufI] === CharCode.NEWLINE) {\n\n // Get semicolon\n let semI = bufI - 5;\n if (chunk[semI] !== CharCode.SEMICOLON) {\n semI += 1 | (1 + ~(chunk[semI - 1] === CharCode.SEMICOLON));\n }\n\n // Add the station's name to the trie and get leaf\n [trie, leaf] = add(trie, chunk, minI, semI);\n\n // Update next entry's min\n minI = bufI + 1;\n\n // Get temperature\n const tempV = parseDouble(chunk, semI + 1, bufI);\n\n // If the station existed\n leaf += TrieNodeProto.VALUE_IDX;\n if (trie[leaf] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf], tempV);\n } else {\n // Add the new station's value\n trie[leaf] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n // Prepend any incomplete entry to the next chunk\n chunk.copyWithin(0, minI, bufI);\n\n // Update indices for the next chunk\n bufI -= minI;\n minI = 0;\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = mins[ai] <= mins[bi] ? mins[ai] : mins[bi];\n maxes[ai] = maxes[ai] >= maxes[bi] ? maxes[ai] : maxes[bi];\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], + "mappings": "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", "names": ["availableParallelism", "fileURLToPath", "isMainThread", "parentPort", "closeSync", "createWriteStream", "openSync", "stdout", "fstatSync", "readSync", "clamp", "value", "min", "max", "getFileChunks", "fd", "target", "maxLineLength", "minSize", "size", "fstatSync", "chunkSize", "buffer", "chunks", "start", "end", "bytesRead", "readSync", "newline", "getHighWaterMark", "add", "trie", "key", "min", "max", "index", "child", "grow", "createTrie", "id", "size", "trie", "grow", "minSize", "length", "next", "i", "mergeLeft", "tries", "at", "bt", "mergeFn", "grown", "queue", "Q", "q", "ai", "bi", "bvi", "avi", "bn", "ri", "rt", "li", "lt", "print", "key", "trieIndex", "stream", "separator", "callbackFn", "stack", "top", "tail", "trieI", "childPtr", "numChild", "childI", "childTrieI", "valueIndex", "Worker", "createWorker", "workerPath", "worker", "err", "code", "exec", "req", "resolve", "run", "filePath", "workerPath", "maxWorkers", "outPath", "clamp", "fd", "openSync", "chunks", "getFileChunks", "valBuf", "mins", "maxes", "counts", "sums", "tries", "unmerged", "tasks", "i", "worker", "createWorker", "exec", "res", "a", "id", "closeSync", "out", "createWriteStream", "stdout", "buffer", "print", "printStation", "stream", "name", "nameLen", "vi", "avg", "readSync", "CHAR_ZERO_11", "CHAR_ZERO_111", "parseDouble", "b", "min", "max", "run", "end", "fd", "id", "start", "counts", "maxes", "mins", "sums", "chunkSize", "getHighWaterMark", "chunk", "bufI", "leaf", "minI", "stations", "trie", "createTrie", "bytesRead", "readSync", "N", "semI", "add", "tempV", "parseDouble", "updateStation", "newStation", "index", "temp", "merge", "a", "b", "tries", "mergeStations", "ai", "bi", "mergeLeft", "isMainThread", "workerPath", "fileURLToPath", "run", "availableParallelism", "parentPort", "msg", "merge"] } diff --git a/src/main/nodejs/havelessbemore/src/worker.ts b/src/main/nodejs/havelessbemore/src/worker.ts index b09aaa4..883fefe 100644 --- a/src/main/nodejs/havelessbemore/src/worker.ts +++ b/src/main/nodejs/havelessbemore/src/worker.ts @@ -113,8 +113,8 @@ export function merge({ function mergeStations(ai: number, bi: number): void { ai <<= 3; bi <<= 3; - mins[ai] = Math.min(mins[ai], mins[bi]); - maxes[ai] = Math.max(maxes[ai], maxes[bi]); + mins[ai] = mins[ai] <= mins[bi] ? mins[ai] : mins[bi]; + maxes[ai] = maxes[ai] >= maxes[bi] ? maxes[ai] : maxes[bi]; counts[ai >> 1] += counts[bi >> 1]; sums[ai >> 2] += sums[bi >> 2]; } From 8160806ec16d0206914f9c80b5910f6533c58420 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Mon, 27 May 2024 00:58:48 -0400 Subject: [PATCH 61/69] Update benchmark results --- src/main/nodejs/havelessbemore/README.md | 6 +++--- src/main/nodejs/havelessbemore/dist/index.mjs | 4 ++-- .../nodejs/havelessbemore/dist/index.mjs.map | 6 +++--- src/main/nodejs/havelessbemore/src/worker.ts | 16 ++++++---------- 4 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/main/nodejs/havelessbemore/README.md b/src/main/nodejs/havelessbemore/README.md index d524569..90d99ca 100644 --- a/src/main/nodejs/havelessbemore/README.md +++ b/src/main/nodejs/havelessbemore/README.md @@ -14,9 +14,9 @@ ### Results -- Min: 12.0s -- Avg: 12.8s -- Max: 13.1s +- Min: 11.4s +- Avg: 11.9s +- Max: 12.1s - Samples: 10 runs, 5s apart #### Specs: diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index c8bc082..0ee9fc2 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -1,3 +1,3 @@ -import{availableParallelism as Y}from"node:os";import{fileURLToPath as Q}from"node:url";import{isMainThread as $,parentPort as g}from"node:worker_threads";import{closeSync as x,createWriteStream as F,openSync as G}from"node:fs";import{stdout as K}from"node:process";import{fstatSync as B,readSync as v}from"fs";function X(e,r,t){return e>r?e<=t?e:t:r}function b(e,r,t,a=0){let u=B(e).size,s=Math.max(a,Math.floor(u/r)),I=Buffer.allocUnsafe(t),p=[],c=0;for(let o=s;o=0&&ie.length&&(e=S(e,s+218)),e[0]+=218,e[u+0]=s,e[s+0]=e[1]),u=s}return[e,u]}function N(e=0,r=655360){r=Math.max(219,r);let t=new Int32Array(new SharedArrayBuffer(r<<2));return t[0]=219,t[1]=e,t}function S(e,r=0){let t=e[0];r=Math.max(r,Math.ceil(t*1.618033988749895));let a=new Int32Array(new SharedArrayBuffer(r<<2));for(let u=0;ue[c].length&&(e[c]=S(e[c],M+2),u.push(c)),e[c][0]+=2,e[c][o+0]=M,e[c][M+0]=h,e[c][M+1]=m;else{let n=e[c][M+0];c!==n&&(M=e[c][M+1]),s.push([n,M,h,m])}}o+=1,i+=1}}s.splice(0,I)}while(s.length>0);return u}function O(e,r,t,a,u="",s){let I=new Array(r.length+1);I[0]=[t,3,0];let p=0,c=!1;do{let[o,f,i]=I[p];if(i>=216){--p;continue}I[p][1]+=1,++I[p][2];let l=e[o][f+0];if(l===0)continue;let D=e[o][l+0];o!==D&&(l=e[o][l+1],o=D),r[p]=i+32,I[++p]=[o,l+2,0];let m=e[o][l+1];m!==0&&(c&&a.write(u),c=!0,s(a,r,p,m))}while(p>=0)}import{Worker as Z}from"node:worker_threads";function C(e){let r=new Z(e);return r.on("error",t=>{throw t}),r.on("messageerror",t=>{throw t}),r.on("exit",t=>{if(t>1||t<0)throw new Error(`Worker ${r.threadId} exited with code ${t}`)}),r}function d(e,r){return new Promise(t=>{e.once("message",t),e.postMessage(r)})}async function P(e,r,t,a=""){t=X(t,1,512);let u=G(e,"r"),s=b(u,t,107,16384);t=s.length;let I=new SharedArrayBuffer(1e4*t+1<<4),p=new Int16Array(I),c=new Int16Array(I,2),o=new Uint32Array(I,4),f=new Float64Array(I,8),i=new Array(t),l=[],D=new Array(t);for(let n=0;n{let _=E.id;for(i[_]=E.trie;l.length>0;){let y=await d(R,{type:1,a:_,b:l.pop(),counts:o,maxes:c,mins:p,sums:f,tries:i});for(let A of y.ids)i[A]=y.tries[A]}return l.push(_),R.terminate()})}await Promise.all(D),x(u);let m=F(a,{fd:a.length<1?K.fd:void 0,flags:"a",highWaterMark:1048576}),h=Buffer.allocUnsafe(100);m.write("{"),O(i,h,l[0],m,", ",M),m.end(`} -`);function M(n,R,E,_){let y=Math.round(f[_<<1]/o[_<<2]);n.write(R.toString("utf8",0,E)),n.write("="),n.write((p[_<<3]/10).toFixed(1)),n.write("/"),n.write((y/10).toFixed(1)),n.write("/"),n.write((c[_<<3]/10).toFixed(1))}}import{readSync as V}from"fs";var U=11*48,q=111*48;function H(e,r,t){return e[r]===45?(++r,r+4>t?U-10*e[r]-e[r+2]:q-100*e[r]-10*e[r+1]-e[r+3]):r+4>t?10*e[r]+e[r+2]-U:100*e[r]+10*e[r+1]+e[r+3]-q}function W({end:e,fd:r,id:t,start:a,counts:u,maxes:s,mins:I,sums:p}){let c=w(e-a),o=Buffer.allocUnsafe(c+107),f=0,i=0,l=0,D=t*1e4+1,m=N(t);for(;a=R?s[n]:R,++u[n>>1],p[n>>2]+=R}return{id:t,trie:m}}function k({a:e,b:r,tries:t,counts:a,maxes:u,mins:s,sums:I}){function p(o,f){o<<=3,f<<=3,s[o]=s[o]<=s[f]?s[o]:s[f],u[o]=u[o]>=u[f]?u[o]:u[f],a[o>>1]+=a[f>>1],I[o>>2]+=I[f>>2]}return{ids:T(t,e,r,p),tries:t}}if($){let e=Q(import.meta.url);P(process.argv[2],e,Y())}else g.addListener("message",e=>{if(e.type===0)g.postMessage(W(e));else if(e.type===1)g.postMessage(k(e));else throw new Error("Unknown message type")}); +import{availableParallelism as Y}from"node:os";import{fileURLToPath as Q}from"node:url";import{isMainThread as $,parentPort as g}from"node:worker_threads";import{closeSync as Z,createWriteStream as F,openSync as G}from"node:fs";import{stdout as K}from"node:process";import{fstatSync as B,readSync as x}from"fs";function X(e,r,t){return e>r?e<=t?e:t:r}function b(e,r,t,a=0){let c=B(e).size,n=Math.max(a,Math.floor(c/r)),I=Buffer.allocUnsafe(t),p=[],f=0;for(let o=n;o=0&&ie.length&&(e=S(e,n+218)),e[0]+=218,e[c+0]=n,e[n+0]=e[1]),c=n}return[e,c]}function N(e=0,r=655360){r=Math.max(219,r);let t=new Int32Array(new SharedArrayBuffer(r<<2));return t[0]=219,t[1]=e,t}function S(e,r=0){let t=e[0];r=Math.max(r,Math.ceil(t*1.618033988749895));let a=new Int32Array(new SharedArrayBuffer(r<<2));for(let c=0;ce[f].length&&(e[f]=S(e[f],M+2),c.push(f)),e[f][0]+=2,e[f][o+0]=M,e[f][M+0]=h,e[f][M+1]=m;else{let u=e[f][M+0];f!==u&&(M=e[f][M+1]),n.push([u,M,h,m])}}o+=1,i+=1}}n.splice(0,I)}while(n.length>0);return c}function O(e,r,t,a,c="",n){let I=new Array(r.length+1);I[0]=[t,3,0];let p=0,f=!1;do{let[o,s,i]=I[p];if(i>=216){--p;continue}I[p][1]+=1,++I[p][2];let l=e[o][s+0];if(l===0)continue;let D=e[o][l+0];o!==D&&(l=e[o][l+1],o=D),r[p]=i+32,I[++p]=[o,l+2,0];let m=e[o][l+1];m!==0&&(f&&a.write(c),f=!0,n(a,r,p,m))}while(p>=0)}import{Worker as v}from"node:worker_threads";function C(e){let r=new v(e);return r.on("error",t=>{throw t}),r.on("messageerror",t=>{throw t}),r.on("exit",t=>{if(t>1||t<0)throw new Error(`Worker ${r.threadId} exited with code ${t}`)}),r}function d(e,r){return new Promise(t=>{e.once("message",t),e.postMessage(r)})}async function P(e,r,t,a=""){t=X(t,1,512);let c=G(e,"r"),n=b(c,t,107,16384);t=n.length;let I=new SharedArrayBuffer(1e4*t+1<<4),p=new Int16Array(I),f=new Int16Array(I,2),o=new Uint32Array(I,4),s=new Float64Array(I,8),i=new Array(t),l=[],D=new Array(t);for(let u=0;u{let _=E.id;for(i[_]=E.trie;l.length>0;){let y=await d(R,{type:1,a:_,b:l.pop(),counts:o,maxes:f,mins:p,sums:s,tries:i});for(let A of y.ids)i[A]=y.tries[A]}return l.push(_),R.terminate()})}await Promise.all(D),Z(c);let m=F(a,{fd:a.length<1?K.fd:void 0,flags:"a",highWaterMark:1048576}),h=Buffer.allocUnsafe(100);m.write("{"),O(i,h,l[0],m,", ",M),m.end(`} +`);function M(u,R,E,_){let y=Math.round(s[_<<1]/o[_<<2]);u.write(R.toString("utf8",0,E)),u.write("="),u.write((p[_<<3]/10).toFixed(1)),u.write("/"),u.write((y/10).toFixed(1)),u.write("/"),u.write((f[_<<3]/10).toFixed(1))}}import{readSync as V}from"fs";var U=11*48,q=111*48;function H(e,r,t){return e[r]===45?(++r,r+4>t?U-10*e[r]-e[r+2]:q-100*e[r]-10*e[r+1]-e[r+3]):r+4>t?10*e[r]+e[r+2]-U:100*e[r]+10*e[r+1]+e[r+3]-q}function W({end:e,fd:r,id:t,start:a,counts:c,maxes:n,mins:I,sums:p}){let f=w(e-a),o=Buffer.allocUnsafe(f+107),s=0,i=0,l=0,D=t*1e4,m=N(t);for(;a=R?n[u]:R,++c[u>>1],p[u>>2]+=R}return{id:t,trie:m}}function k({a:e,b:r,tries:t,counts:a,maxes:c,mins:n,sums:I}){function p(o,s){o<<=3,s<<=3,n[o]=n[o]<=n[s]?n[o]:n[s],c[o]=n[o]>=n[s]?n[o]:n[s],a[o>>1]+=a[s>>1],I[o>>2]+=I[s>>2]}return{ids:T(t,e,r,p),tries:t}}if($){let e=Q(import.meta.url);P(process.argv[2],e,Y())}else g.addListener("message",e=>{if(e.type===0)g.postMessage(W(e));else if(e.type===1)g.postMessage(k(e));else throw new Error("Unknown message type")}); //# sourceMappingURL=index.mjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index 3cdfd2f..25d8513 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../src/index.ts", "../src/main.ts", "../src/utils/stream.ts", "../src/utils/utf8Trie.ts", "../src/utils/worker.ts", "../src/worker.ts", "../src/utils/parse.ts"], - "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport { RequestType, type Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", (msg: Request) => {\n if (msg.type === RequestType.PROCESS) {\n parentPort!.postMessage(runWorker(msg as ProcessRequest));\n } else if (msg.type === RequestType.MERGE) {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { closeSync, createWriteStream, openSync, WriteStream } from \"node:fs\";\nimport { stdout } from \"node:process\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\nimport { RequestType } from \"./types/request\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Open the given file\n const fd = openSync(filePath, \"r\");\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = getFileChunks(\n fd,\n maxWorkers,\n BRC.MAX_ENTRY_LEN,\n Config.HIGH_WATER_MARK_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: RequestType.PROCESS,\n counts,\n end: chunks[i][1],\n fd,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[a] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: RequestType.MERGE,\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Close the file\n closeSync(fd);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? stdout.fd : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { fstatSync, readSync } from \"fs\";\nimport { Config } from \"../constants/config\";\nimport { CharCode } from \"../constants/utf8\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport function getFileChunks(\n fd: number,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): [number, number][] {\n // Get the file's size\n const size = fstatSync(fd).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const bytesRead = readSync(fd, buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CharCode.NEWLINE);\n // If found\n if (newline >= 0 && newline < bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= Config.HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, Config.HIGH_WATER_MARK_MIN, Config.HIGH_WATER_MARK_MAX);\n}\n", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown: number[] = [];\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.push(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return grown;\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"node:worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { readSync } from \"fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\n\nexport function run({\n end,\n fd,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): ProcessResponse {\n\n // Initialize constants\n const chunkSize = getHighWaterMark(end - start);\n const chunk = Buffer.allocUnsafe(chunkSize + BRC.MAX_ENTRY_LEN);\n\n // Initialize variables\n let bufI = 0;\n let leaf = 0;\n let minI = 0;\n let stations = id * BRC.MAX_STATIONS + 1;\n let trie = createTrie(id);\n\n // For each chunk\n while (start < end) {\n\n // Read the chunk into memory\n const bytesRead = readSync(fd, chunk, bufI, chunkSize, start);\n start += bytesRead;\n\n // For each byte\n for (const N = bufI + bytesRead; bufI < N; ++bufI) {\n\n // If newline\n if (chunk[bufI] === CharCode.NEWLINE) {\n\n // Get semicolon\n let semI = bufI - 5;\n if (chunk[semI] !== CharCode.SEMICOLON) {\n semI += 1 | (1 + ~(chunk[semI - 1] === CharCode.SEMICOLON));\n }\n\n // Add the station's name to the trie and get leaf\n [trie, leaf] = add(trie, chunk, minI, semI);\n\n // Update next entry's min\n minI = bufI + 1;\n\n // Get temperature\n const tempV = parseDouble(chunk, semI + 1, bufI);\n\n // If the station existed\n leaf += TrieNodeProto.VALUE_IDX;\n if (trie[leaf] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf], tempV);\n } else {\n // Add the new station's value\n trie[leaf] = stations;\n newStation(stations++, tempV);\n }\n }\n }\n\n // Prepend any incomplete entry to the next chunk\n chunk.copyWithin(0, minI, bufI);\n\n // Update indices for the next chunk\n bufI -= minI;\n minI = 0;\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = mins[ai] <= mins[bi] ? mins[ai] : mins[bi];\n maxes[ai] = maxes[ai] >= maxes[bi] ? maxes[ai] : maxes[bi];\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], - "mappings": "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", - "names": ["availableParallelism", "fileURLToPath", "isMainThread", "parentPort", "closeSync", "createWriteStream", "openSync", "stdout", "fstatSync", "readSync", "clamp", "value", "min", "max", "getFileChunks", "fd", "target", "maxLineLength", "minSize", "size", "fstatSync", "chunkSize", "buffer", "chunks", "start", "end", "bytesRead", "readSync", "newline", "getHighWaterMark", "add", "trie", "key", "min", "max", "index", "child", "grow", "createTrie", "id", "size", "trie", "grow", "minSize", "length", "next", "i", "mergeLeft", "tries", "at", "bt", "mergeFn", "grown", "queue", "Q", "q", "ai", "bi", "bvi", "avi", "bn", "ri", "rt", "li", "lt", "print", "key", "trieIndex", "stream", "separator", "callbackFn", "stack", "top", "tail", "trieI", "childPtr", "numChild", "childI", "childTrieI", "valueIndex", "Worker", "createWorker", "workerPath", "worker", "err", "code", "exec", "req", "resolve", "run", "filePath", "workerPath", "maxWorkers", "outPath", "clamp", "fd", "openSync", "chunks", "getFileChunks", "valBuf", "mins", "maxes", "counts", "sums", "tries", "unmerged", "tasks", "i", "worker", "createWorker", "exec", "res", "a", "id", "closeSync", "out", "createWriteStream", "stdout", "buffer", "print", "printStation", "stream", "name", "nameLen", "vi", "avg", "readSync", "CHAR_ZERO_11", "CHAR_ZERO_111", "parseDouble", "b", "min", "max", "run", "end", "fd", "id", "start", "counts", "maxes", "mins", "sums", "chunkSize", "getHighWaterMark", "chunk", "bufI", "leaf", "minI", "stations", "trie", "createTrie", "bytesRead", "readSync", "N", "semI", "add", "tempV", "parseDouble", "updateStation", "newStation", "index", "temp", "merge", "a", "b", "tries", "mergeStations", "ai", "bi", "mergeLeft", "isMainThread", "workerPath", "fileURLToPath", "run", "availableParallelism", "parentPort", "msg", "merge"] + "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport { RequestType, type Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", (msg: Request) => {\n if (msg.type === RequestType.PROCESS) {\n parentPort!.postMessage(runWorker(msg as ProcessRequest));\n } else if (msg.type === RequestType.MERGE) {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { closeSync, createWriteStream, openSync, WriteStream } from \"node:fs\";\nimport { stdout } from \"node:process\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\nimport { RequestType } from \"./types/request\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Open the given file\n const fd = openSync(filePath, \"r\");\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = getFileChunks(\n fd,\n maxWorkers,\n BRC.MAX_ENTRY_LEN,\n Config.HIGH_WATER_MARK_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: RequestType.PROCESS,\n counts,\n end: chunks[i][1],\n fd,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[a] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: RequestType.MERGE,\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Close the file\n closeSync(fd);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? stdout.fd : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { fstatSync, readSync } from \"fs\";\nimport { Config } from \"../constants/config\";\nimport { CharCode } from \"../constants/utf8\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport function getFileChunks(\n fd: number,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): [number, number][] {\n // Get the file's size\n const size = fstatSync(fd).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const bytesRead = readSync(fd, buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CharCode.NEWLINE);\n // If found\n if (newline >= 0 && newline < bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= Config.HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, Config.HIGH_WATER_MARK_MIN, Config.HIGH_WATER_MARK_MAX);\n}\n", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown: number[] = [];\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.push(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return grown;\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"node:worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { readSync } from \"fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\n\nexport function run({\n end,\n fd,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): ProcessResponse {\n // Initialize constants\n const chunkSize = getHighWaterMark(end - start);\n const chunk = Buffer.allocUnsafe(chunkSize + BRC.MAX_ENTRY_LEN);\n\n // Initialize variables\n let bufI = 0;\n let leaf = 0;\n let minI = 0;\n let stations = id * BRC.MAX_STATIONS;\n let trie = createTrie(id);\n\n // For each chunk\n while (start < end) {\n // Read the chunk into memory\n const bytesRead = readSync(fd, chunk, bufI, chunkSize, start);\n start += bytesRead;\n\n // For each byte\n for (const N = bufI + bytesRead; bufI < N; ++bufI) {\n // If newline\n if (chunk[bufI] === CharCode.NEWLINE) {\n // Get semicolon\n let semI = bufI - 5;\n if (chunk[semI] !== CharCode.SEMICOLON) {\n semI += 1 | (1 + ~(chunk[semI - 1] === CharCode.SEMICOLON));\n }\n\n // Add the station's name to the trie and get leaf\n [trie, leaf] = add(trie, chunk, minI, semI);\n\n // Update next entry's min\n minI = bufI + 1;\n\n // Get temperature\n const temp = parseDouble(chunk, semI + 1, bufI);\n\n // If the station existed\n leaf += TrieNodeProto.VALUE_IDX;\n if (trie[leaf] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf], temp);\n } else {\n // Add the new station's value\n trie[leaf] = ++stations;\n newStation(stations, temp);\n }\n }\n }\n\n // Prepend any incomplete entry to the next chunk\n chunk.copyWithin(0, minI, bufI);\n\n // Update indices for the next chunk\n bufI -= minI;\n minI = 0;\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = mins[ai] <= mins[bi] ? mins[ai] : mins[bi];\n maxes[ai] = mins[ai] >= mins[bi] ? mins[ai] : mins[bi];\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], + "mappings": "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", + "names": ["availableParallelism", "fileURLToPath", "isMainThread", "parentPort", "closeSync", "createWriteStream", "openSync", "stdout", "fstatSync", "readSync", "clamp", "value", "min", "max", "getFileChunks", "fd", "target", "maxLineLength", "minSize", "size", "fstatSync", "chunkSize", "buffer", "chunks", "start", "end", "bytesRead", "readSync", "newline", "getHighWaterMark", "add", "trie", "key", "min", "max", "index", "child", "grow", "createTrie", "id", "size", "trie", "grow", "minSize", "length", "next", "i", "mergeLeft", "tries", "at", "bt", "mergeFn", "grown", "queue", "Q", "q", "ai", "bi", "bvi", "avi", "bn", "ri", "rt", "li", "lt", "print", "key", "trieIndex", "stream", "separator", "callbackFn", "stack", "top", "tail", "trieI", "childPtr", "numChild", "childI", "childTrieI", "valueIndex", "Worker", "createWorker", "workerPath", "worker", "err", "code", "exec", "req", "resolve", "run", "filePath", "workerPath", "maxWorkers", "outPath", "clamp", "fd", "openSync", "chunks", "getFileChunks", "valBuf", "mins", "maxes", "counts", "sums", "tries", "unmerged", "tasks", "i", "worker", "createWorker", "exec", "res", "a", "id", "closeSync", "out", "createWriteStream", "stdout", "buffer", "print", "printStation", "stream", "name", "nameLen", "vi", "avg", "readSync", "CHAR_ZERO_11", "CHAR_ZERO_111", "parseDouble", "b", "min", "max", "run", "end", "fd", "id", "start", "counts", "maxes", "mins", "sums", "chunkSize", "getHighWaterMark", "chunk", "bufI", "leaf", "minI", "stations", "trie", "createTrie", "bytesRead", "readSync", "N", "semI", "add", "temp", "parseDouble", "updateStation", "newStation", "index", "merge", "a", "b", "tries", "mergeStations", "ai", "bi", "mergeLeft", "isMainThread", "workerPath", "fileURLToPath", "run", "availableParallelism", "parentPort", "msg", "merge"] } diff --git a/src/main/nodejs/havelessbemore/src/worker.ts b/src/main/nodejs/havelessbemore/src/worker.ts index 883fefe..263af0b 100644 --- a/src/main/nodejs/havelessbemore/src/worker.ts +++ b/src/main/nodejs/havelessbemore/src/worker.ts @@ -22,7 +22,6 @@ export function run({ mins, sums, }: ProcessRequest): ProcessResponse { - // Initialize constants const chunkSize = getHighWaterMark(end - start); const chunk = Buffer.allocUnsafe(chunkSize + BRC.MAX_ENTRY_LEN); @@ -31,22 +30,19 @@ export function run({ let bufI = 0; let leaf = 0; let minI = 0; - let stations = id * BRC.MAX_STATIONS + 1; + let stations = id * BRC.MAX_STATIONS; let trie = createTrie(id); // For each chunk while (start < end) { - // Read the chunk into memory const bytesRead = readSync(fd, chunk, bufI, chunkSize, start); start += bytesRead; // For each byte for (const N = bufI + bytesRead; bufI < N; ++bufI) { - // If newline if (chunk[bufI] === CharCode.NEWLINE) { - // Get semicolon let semI = bufI - 5; if (chunk[semI] !== CharCode.SEMICOLON) { @@ -60,17 +56,17 @@ export function run({ minI = bufI + 1; // Get temperature - const tempV = parseDouble(chunk, semI + 1, bufI); + const temp = parseDouble(chunk, semI + 1, bufI); // If the station existed leaf += TrieNodeProto.VALUE_IDX; if (trie[leaf] !== Trie.NULL) { // Update the station's value - updateStation(trie[leaf], tempV); + updateStation(trie[leaf], temp); } else { // Add the new station's value - trie[leaf] = stations; - newStation(stations++, tempV); + trie[leaf] = ++stations; + newStation(stations, temp); } } } @@ -114,7 +110,7 @@ export function merge({ ai <<= 3; bi <<= 3; mins[ai] = mins[ai] <= mins[bi] ? mins[ai] : mins[bi]; - maxes[ai] = maxes[ai] >= maxes[bi] ? maxes[ai] : maxes[bi]; + maxes[ai] = mins[ai] >= mins[bi] ? mins[ai] : mins[bi]; counts[ai >> 1] += counts[bi >> 1]; sums[ai >> 2] += sums[bi >> 2]; } From 90433574e8d1bc888923badc5076d67cf2b36e1e Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Mon, 27 May 2024 01:44:18 -0400 Subject: [PATCH 62/69] Refactor worker --- src/main/nodejs/havelessbemore/dist/index.mjs | 4 +- .../nodejs/havelessbemore/dist/index.mjs.map | 6 +- src/main/nodejs/havelessbemore/src/worker.ts | 96 ++++++++++--------- 3 files changed, 54 insertions(+), 52 deletions(-) diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index 0ee9fc2..c7c69d8 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -1,3 +1,3 @@ -import{availableParallelism as Y}from"node:os";import{fileURLToPath as Q}from"node:url";import{isMainThread as $,parentPort as g}from"node:worker_threads";import{closeSync as Z,createWriteStream as F,openSync as G}from"node:fs";import{stdout as K}from"node:process";import{fstatSync as B,readSync as x}from"fs";function X(e,r,t){return e>r?e<=t?e:t:r}function b(e,r,t,a=0){let c=B(e).size,n=Math.max(a,Math.floor(c/r)),I=Buffer.allocUnsafe(t),p=[],f=0;for(let o=n;o=0&&ie.length&&(e=S(e,n+218)),e[0]+=218,e[c+0]=n,e[n+0]=e[1]),c=n}return[e,c]}function N(e=0,r=655360){r=Math.max(219,r);let t=new Int32Array(new SharedArrayBuffer(r<<2));return t[0]=219,t[1]=e,t}function S(e,r=0){let t=e[0];r=Math.max(r,Math.ceil(t*1.618033988749895));let a=new Int32Array(new SharedArrayBuffer(r<<2));for(let c=0;ce[f].length&&(e[f]=S(e[f],M+2),c.push(f)),e[f][0]+=2,e[f][o+0]=M,e[f][M+0]=h,e[f][M+1]=m;else{let u=e[f][M+0];f!==u&&(M=e[f][M+1]),n.push([u,M,h,m])}}o+=1,i+=1}}n.splice(0,I)}while(n.length>0);return c}function O(e,r,t,a,c="",n){let I=new Array(r.length+1);I[0]=[t,3,0];let p=0,f=!1;do{let[o,s,i]=I[p];if(i>=216){--p;continue}I[p][1]+=1,++I[p][2];let l=e[o][s+0];if(l===0)continue;let D=e[o][l+0];o!==D&&(l=e[o][l+1],o=D),r[p]=i+32,I[++p]=[o,l+2,0];let m=e[o][l+1];m!==0&&(f&&a.write(c),f=!0,n(a,r,p,m))}while(p>=0)}import{Worker as v}from"node:worker_threads";function C(e){let r=new v(e);return r.on("error",t=>{throw t}),r.on("messageerror",t=>{throw t}),r.on("exit",t=>{if(t>1||t<0)throw new Error(`Worker ${r.threadId} exited with code ${t}`)}),r}function d(e,r){return new Promise(t=>{e.once("message",t),e.postMessage(r)})}async function P(e,r,t,a=""){t=X(t,1,512);let c=G(e,"r"),n=b(c,t,107,16384);t=n.length;let I=new SharedArrayBuffer(1e4*t+1<<4),p=new Int16Array(I),f=new Int16Array(I,2),o=new Uint32Array(I,4),s=new Float64Array(I,8),i=new Array(t),l=[],D=new Array(t);for(let u=0;u{let _=E.id;for(i[_]=E.trie;l.length>0;){let y=await d(R,{type:1,a:_,b:l.pop(),counts:o,maxes:f,mins:p,sums:s,tries:i});for(let A of y.ids)i[A]=y.tries[A]}return l.push(_),R.terminate()})}await Promise.all(D),Z(c);let m=F(a,{fd:a.length<1?K.fd:void 0,flags:"a",highWaterMark:1048576}),h=Buffer.allocUnsafe(100);m.write("{"),O(i,h,l[0],m,", ",M),m.end(`} -`);function M(u,R,E,_){let y=Math.round(s[_<<1]/o[_<<2]);u.write(R.toString("utf8",0,E)),u.write("="),u.write((p[_<<3]/10).toFixed(1)),u.write("/"),u.write((y/10).toFixed(1)),u.write("/"),u.write((f[_<<3]/10).toFixed(1))}}import{readSync as V}from"fs";var U=11*48,q=111*48;function H(e,r,t){return e[r]===45?(++r,r+4>t?U-10*e[r]-e[r+2]:q-100*e[r]-10*e[r+1]-e[r+3]):r+4>t?10*e[r]+e[r+2]-U:100*e[r]+10*e[r+1]+e[r+3]-q}function W({end:e,fd:r,id:t,start:a,counts:c,maxes:n,mins:I,sums:p}){let f=w(e-a),o=Buffer.allocUnsafe(f+107),s=0,i=0,l=0,D=t*1e4,m=N(t);for(;a=R?n[u]:R,++c[u>>1],p[u>>2]+=R}return{id:t,trie:m}}function k({a:e,b:r,tries:t,counts:a,maxes:c,mins:n,sums:I}){function p(o,s){o<<=3,s<<=3,n[o]=n[o]<=n[s]?n[o]:n[s],c[o]=n[o]>=n[s]?n[o]:n[s],a[o>>1]+=a[s>>1],I[o>>2]+=I[s>>2]}return{ids:T(t,e,r,p),tries:t}}if($){let e=Q(import.meta.url);P(process.argv[2],e,Y())}else g.addListener("message",e=>{if(e.type===0)g.postMessage(W(e));else if(e.type===1)g.postMessage(k(e));else throw new Error("Unknown message type")}); +import{availableParallelism as Y}from"node:os";import{fileURLToPath as Q}from"node:url";import{isMainThread as $,parentPort as g}from"node:worker_threads";import{closeSync as x,createWriteStream as F,openSync as G}from"node:fs";import{stdout as K}from"node:process";import{fstatSync as B,readSync as v}from"fs";function X(e,r,t){return e>r?e<=t?e:t:r}function b(e,r,t,m=0){let s=B(e).size,f=Math.max(m,Math.floor(s/r)),I=Buffer.allocUnsafe(t),i=[],o=0;for(let u=f;u=0&&ce.length&&(e=T(e,f+218)),e[0]+=218,e[s+0]=f,e[f+0]=e[1]),s=f}return[e,s]}function N(e=0,r=655360){r=Math.max(219,r);let t=new Int32Array(new SharedArrayBuffer(r<<2));return t[0]=219,t[1]=e,t}function T(e,r=0){let t=e[0];r=Math.max(r,Math.ceil(t*1.618033988749895));let m=new Int32Array(new SharedArrayBuffer(r<<2));for(let s=0;se[o].length&&(e[o]=T(e[o],l+2),s.push(o)),e[o][0]+=2,e[o][u+0]=l,e[o][l+0]=h,e[o][l+1]=a;else{let n=e[o][l+0];o!==n&&(l=e[o][l+1]),f.push([n,l,h,a])}}u+=1,c+=1}}f.splice(0,I)}while(f.length>0);return s}function O(e,r,t,m,s="",f){let I=new Array(r.length+1);I[0]=[t,3,0];let i=0,o=!1;do{let[u,M,c]=I[i];if(c>=216){--i;continue}I[i][1]+=1,++I[i][2];let p=e[u][M+0];if(p===0)continue;let _=e[u][p+0];u!==_&&(p=e[u][p+1],u=_),r[i]=c+32,I[++i]=[u,p+2,0];let a=e[u][p+1];a!==0&&(o&&m.write(s),o=!0,f(m,r,i,a))}while(i>=0)}import{Worker as Z}from"node:worker_threads";function C(e){let r=new Z(e);return r.on("error",t=>{throw t}),r.on("messageerror",t=>{throw t}),r.on("exit",t=>{if(t>1||t<0)throw new Error(`Worker ${r.threadId} exited with code ${t}`)}),r}function d(e,r){return new Promise(t=>{e.once("message",t),e.postMessage(r)})}async function P(e,r,t,m=""){t=X(t,1,512);let s=G(e,"r"),f=b(s,t,107,16384);t=f.length;let I=new SharedArrayBuffer(1e4*t+1<<4),i=new Int16Array(I),o=new Int16Array(I,2),u=new Uint32Array(I,4),M=new Float64Array(I,8),c=new Array(t),p=[],_=new Array(t);for(let n=0;n{let D=E.id;for(c[D]=E.trie;p.length>0;){let y=await d(R,{type:1,a:D,b:p.pop(),counts:u,maxes:o,mins:i,sums:M,tries:c});for(let A of y.ids)c[A]=y.tries[A]}return p.push(D),R.terminate()})}await Promise.all(_),x(s);let a=F(m,{fd:m.length<1?K.fd:void 0,flags:"a",highWaterMark:1048576}),h=Buffer.allocUnsafe(100);a.write("{"),O(c,h,p[0],a,", ",l),a.end(`} +`);function l(n,R,E,D){let y=Math.round(M[D<<1]/u[D<<2]);n.write(R.toString("utf8",0,E)),n.write("="),n.write((i[D<<3]/10).toFixed(1)),n.write("/"),n.write((y/10).toFixed(1)),n.write("/"),n.write((o[D<<3]/10).toFixed(1))}}import{readSync as V}from"fs";var U=11*48,q=111*48;function H(e,r,t){return e[r]===45?(++r,r+4>t?U-10*e[r]-e[r+2]:q-100*e[r]-10*e[r+1]-e[r+3]):r+4>t?10*e[r]+e[r+2]-U:100*e[r]+10*e[r+1]+e[r+3]-q}function W({end:e,fd:r,id:t,start:m,counts:s,maxes:f,mins:I,sums:i}){let o=(n,R)=>{I[n<<3]=R,f[n<<3]=R,s[n<<2]=1,i[n<<1]=R},u=(n,R)=>{n<<=3,I[n]=I[n]<=R?I[n]:R,f[n]=f[n]>=R?f[n]:R,++s[n>>1],i[n>>2]+=R},M=w(e-m),c=Buffer.allocUnsafe(M+107),p=0,_=0,a=0,h=t*1e4,l=N(t);for(;m{o<<=3,u<<=3,f[o]=f[o]<=f[u]?f[o]:f[u],s[o]=s[o]>=s[u]?s[o]:s[u],m[o>>1]+=m[u>>1],I[o>>2]+=I[u>>2]}),tries:t}}if($){let e=Q(import.meta.url);P(process.argv[2],e,Y())}else g.addListener("message",e=>{if(e.type===0)g.postMessage(W(e));else if(e.type===1)g.postMessage(k(e));else throw new Error("Unknown message type")}); //# sourceMappingURL=index.mjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index 25d8513..4b9a027 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../src/index.ts", "../src/main.ts", "../src/utils/stream.ts", "../src/utils/utf8Trie.ts", "../src/utils/worker.ts", "../src/worker.ts", "../src/utils/parse.ts"], - "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport { RequestType, type Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", (msg: Request) => {\n if (msg.type === RequestType.PROCESS) {\n parentPort!.postMessage(runWorker(msg as ProcessRequest));\n } else if (msg.type === RequestType.MERGE) {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { closeSync, createWriteStream, openSync, WriteStream } from \"node:fs\";\nimport { stdout } from \"node:process\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\nimport { RequestType } from \"./types/request\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Open the given file\n const fd = openSync(filePath, \"r\");\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = getFileChunks(\n fd,\n maxWorkers,\n BRC.MAX_ENTRY_LEN,\n Config.HIGH_WATER_MARK_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: RequestType.PROCESS,\n counts,\n end: chunks[i][1],\n fd,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[a] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: RequestType.MERGE,\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Close the file\n closeSync(fd);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? stdout.fd : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { fstatSync, readSync } from \"fs\";\nimport { Config } from \"../constants/config\";\nimport { CharCode } from \"../constants/utf8\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport function getFileChunks(\n fd: number,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): [number, number][] {\n // Get the file's size\n const size = fstatSync(fd).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const bytesRead = readSync(fd, buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CharCode.NEWLINE);\n // If found\n if (newline >= 0 && newline < bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= Config.HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, Config.HIGH_WATER_MARK_MIN, Config.HIGH_WATER_MARK_MAX);\n}\n", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown: number[] = [];\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.push(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return grown;\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"node:worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { readSync } from \"fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\n\nexport function run({\n end,\n fd,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): ProcessResponse {\n // Initialize constants\n const chunkSize = getHighWaterMark(end - start);\n const chunk = Buffer.allocUnsafe(chunkSize + BRC.MAX_ENTRY_LEN);\n\n // Initialize variables\n let bufI = 0;\n let leaf = 0;\n let minI = 0;\n let stations = id * BRC.MAX_STATIONS;\n let trie = createTrie(id);\n\n // For each chunk\n while (start < end) {\n // Read the chunk into memory\n const bytesRead = readSync(fd, chunk, bufI, chunkSize, start);\n start += bytesRead;\n\n // For each byte\n for (const N = bufI + bytesRead; bufI < N; ++bufI) {\n // If newline\n if (chunk[bufI] === CharCode.NEWLINE) {\n // Get semicolon\n let semI = bufI - 5;\n if (chunk[semI] !== CharCode.SEMICOLON) {\n semI += 1 | (1 + ~(chunk[semI - 1] === CharCode.SEMICOLON));\n }\n\n // Add the station's name to the trie and get leaf\n [trie, leaf] = add(trie, chunk, minI, semI);\n\n // Update next entry's min\n minI = bufI + 1;\n\n // Get temperature\n const temp = parseDouble(chunk, semI + 1, bufI);\n\n // If the station existed\n leaf += TrieNodeProto.VALUE_IDX;\n if (trie[leaf] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf], temp);\n } else {\n // Add the new station's value\n trie[leaf] = ++stations;\n newStation(stations, temp);\n }\n }\n }\n\n // Prepend any incomplete entry to the next chunk\n chunk.copyWithin(0, minI, bufI);\n\n // Update indices for the next chunk\n bufI -= minI;\n minI = 0;\n }\n\n function newStation(index: number, temp: number): void {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n }\n\n function updateStation(index: number, temp: number): void {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n function mergeStations(ai: number, bi: number): void {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = mins[ai] <= mins[bi] ? mins[ai] : mins[bi];\n maxes[ai] = mins[ai] >= mins[bi] ? mins[ai] : mins[bi];\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n }\n const ids = mergeLeft(tries, a, b, mergeStations);\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], - "mappings": "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", - "names": ["availableParallelism", "fileURLToPath", "isMainThread", "parentPort", "closeSync", "createWriteStream", "openSync", "stdout", "fstatSync", "readSync", "clamp", "value", "min", "max", "getFileChunks", "fd", "target", "maxLineLength", "minSize", "size", "fstatSync", "chunkSize", "buffer", "chunks", "start", "end", "bytesRead", "readSync", "newline", "getHighWaterMark", "add", "trie", "key", "min", "max", "index", "child", "grow", "createTrie", "id", "size", "trie", "grow", "minSize", "length", "next", "i", "mergeLeft", "tries", "at", "bt", "mergeFn", "grown", "queue", "Q", "q", "ai", "bi", "bvi", "avi", "bn", "ri", "rt", "li", "lt", "print", "key", "trieIndex", "stream", "separator", "callbackFn", "stack", "top", "tail", "trieI", "childPtr", "numChild", "childI", "childTrieI", "valueIndex", "Worker", "createWorker", "workerPath", "worker", "err", "code", "exec", "req", "resolve", "run", "filePath", "workerPath", "maxWorkers", "outPath", "clamp", "fd", "openSync", "chunks", "getFileChunks", "valBuf", "mins", "maxes", "counts", "sums", "tries", "unmerged", "tasks", "i", "worker", "createWorker", "exec", "res", "a", "id", "closeSync", "out", "createWriteStream", "stdout", "buffer", "print", "printStation", "stream", "name", "nameLen", "vi", "avg", "readSync", "CHAR_ZERO_11", "CHAR_ZERO_111", "parseDouble", "b", "min", "max", "run", "end", "fd", "id", "start", "counts", "maxes", "mins", "sums", "chunkSize", "getHighWaterMark", "chunk", "bufI", "leaf", "minI", "stations", "trie", "createTrie", "bytesRead", "readSync", "N", "semI", "add", "temp", "parseDouble", "updateStation", "newStation", "index", "merge", "a", "b", "tries", "mergeStations", "ai", "bi", "mergeLeft", "isMainThread", "workerPath", "fileURLToPath", "run", "availableParallelism", "parentPort", "msg", "merge"] + "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport { RequestType, type Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", (msg: Request) => {\n if (msg.type === RequestType.PROCESS) {\n parentPort!.postMessage(runWorker(msg as ProcessRequest));\n } else if (msg.type === RequestType.MERGE) {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { closeSync, createWriteStream, openSync, WriteStream } from \"node:fs\";\nimport { stdout } from \"node:process\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\nimport { RequestType } from \"./types/request\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Open the given file\n const fd = openSync(filePath, \"r\");\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = getFileChunks(\n fd,\n maxWorkers,\n BRC.MAX_ENTRY_LEN,\n Config.HIGH_WATER_MARK_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: RequestType.PROCESS,\n counts,\n end: chunks[i][1],\n fd,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[a] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: RequestType.MERGE,\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Close the file\n closeSync(fd);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? stdout.fd : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { fstatSync, readSync } from \"fs\";\nimport { Config } from \"../constants/config\";\nimport { CharCode } from \"../constants/utf8\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport function getFileChunks(\n fd: number,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): [number, number][] {\n // Get the file's size\n const size = fstatSync(fd).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const bytesRead = readSync(fd, buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CharCode.NEWLINE);\n // If found\n if (newline >= 0 && newline < bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= Config.HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, Config.HIGH_WATER_MARK_MIN, Config.HIGH_WATER_MARK_MAX);\n}\n", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown: number[] = [];\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.push(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return grown;\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"node:worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { readSync } from \"fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\n\nexport function run({\n end,\n fd,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): ProcessResponse {\n const newStation = (index: number, temp: number): void => {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n };\n\n const updateStation = (index: number, temp: number): void => {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n };\n\n // Initialize constants\n const chunkSize = getHighWaterMark(end - start);\n const chunk = Buffer.allocUnsafe(chunkSize + BRC.MAX_ENTRY_LEN);\n\n // Initialize variables\n let bufI = 0;\n let leaf = 0;\n let minI = 0;\n let stations = id * BRC.MAX_STATIONS;\n let trie = createTrie(id);\n\n // For each chunk\n while (start < end) {\n // Read the chunk into memory\n const bytesRead = Math.min(chunkSize, end - start);\n readSync(fd, chunk, bufI, bytesRead, start);\n start += bytesRead;\n\n // For each byte\n for (const N = bufI + bytesRead; bufI < N; ++bufI) {\n // If not newline\n if (chunk[bufI] !== CharCode.NEWLINE) {\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 5;\n if (chunk[semI] !== CharCode.SEMICOLON) {\n semI += 1 | (1 + ~(chunk[semI - 1] === CharCode.SEMICOLON));\n }\n\n // Add the station's name to the trie and get leaf\n [trie, leaf] = add(trie, chunk, minI, semI);\n\n // Update next entry's min\n minI = bufI + 1;\n\n // Get temperature\n const temp = parseDouble(chunk, semI + 1, bufI);\n\n // If the station existed\n leaf += TrieNodeProto.VALUE_IDX;\n if (trie[leaf] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf], temp);\n } else {\n // Add the new station's value\n trie[leaf] = ++stations;\n newStation(stations, temp);\n }\n }\n\n // Prepend any incomplete entry to the next chunk\n chunk.copyWithin(0, minI, bufI);\n\n // Update indices for the next chunk\n bufI -= minI;\n minI = 0;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n const ids = mergeLeft(tries, a, b, (ai: number, bi: number): void => {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = mins[ai] <= mins[bi] ? mins[ai] : mins[bi];\n maxes[ai] = maxes[ai] >= maxes[bi] ? maxes[ai] : maxes[bi];\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n });\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], + "mappings": "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", + "names": ["availableParallelism", "fileURLToPath", "isMainThread", "parentPort", "closeSync", "createWriteStream", "openSync", "stdout", "fstatSync", "readSync", "clamp", "value", "min", "max", "getFileChunks", "fd", "target", "maxLineLength", "minSize", "size", "fstatSync", "chunkSize", "buffer", "chunks", "start", "end", "bytesRead", "readSync", "newline", "getHighWaterMark", "add", "trie", "key", "min", "max", "index", "child", "grow", "createTrie", "id", "size", "trie", "grow", "minSize", "length", "next", "i", "mergeLeft", "tries", "at", "bt", "mergeFn", "grown", "queue", "Q", "q", "ai", "bi", "bvi", "avi", "bn", "ri", "rt", "li", "lt", "print", "key", "trieIndex", "stream", "separator", "callbackFn", "stack", "top", "tail", "trieI", "childPtr", "numChild", "childI", "childTrieI", "valueIndex", "Worker", "createWorker", "workerPath", "worker", "err", "code", "exec", "req", "resolve", "run", "filePath", "workerPath", "maxWorkers", "outPath", "clamp", "fd", "openSync", "chunks", "getFileChunks", "valBuf", "mins", "maxes", "counts", "sums", "tries", "unmerged", "tasks", "i", "worker", "createWorker", "exec", "res", "a", "id", "closeSync", "out", "createWriteStream", "stdout", "buffer", "print", "printStation", "stream", "name", "nameLen", "vi", "avg", "readSync", "CHAR_ZERO_11", "CHAR_ZERO_111", "parseDouble", "b", "min", "max", "run", "end", "fd", "id", "start", "counts", "maxes", "mins", "sums", "newStation", "index", "temp", "updateStation", "chunkSize", "getHighWaterMark", "chunk", "bufI", "leaf", "minI", "stations", "trie", "createTrie", "bytesRead", "readSync", "N", "semI", "add", "parseDouble", "merge", "a", "b", "tries", "mergeLeft", "ai", "bi", "isMainThread", "workerPath", "fileURLToPath", "run", "availableParallelism", "parentPort", "msg", "merge"] } diff --git a/src/main/nodejs/havelessbemore/src/worker.ts b/src/main/nodejs/havelessbemore/src/worker.ts index 263af0b..d71b648 100644 --- a/src/main/nodejs/havelessbemore/src/worker.ts +++ b/src/main/nodejs/havelessbemore/src/worker.ts @@ -22,6 +22,21 @@ export function run({ mins, sums, }: ProcessRequest): ProcessResponse { + const newStation = (index: number, temp: number): void => { + mins[index << 3] = temp; + maxes[index << 3] = temp; + counts[index << 2] = 1; + sums[index << 1] = temp; + }; + + const updateStation = (index: number, temp: number): void => { + index <<= 3; + mins[index] = mins[index] <= temp ? mins[index] : temp; + maxes[index] = maxes[index] >= temp ? maxes[index] : temp; + ++counts[index >> 1]; + sums[index >> 2] += temp; + }; + // Initialize constants const chunkSize = getHighWaterMark(end - start); const chunk = Buffer.allocUnsafe(chunkSize + BRC.MAX_ENTRY_LEN); @@ -36,38 +51,41 @@ export function run({ // For each chunk while (start < end) { // Read the chunk into memory - const bytesRead = readSync(fd, chunk, bufI, chunkSize, start); + const bytesRead = Math.min(chunkSize, end - start); + readSync(fd, chunk, bufI, bytesRead, start); start += bytesRead; // For each byte for (const N = bufI + bytesRead; bufI < N; ++bufI) { - // If newline - if (chunk[bufI] === CharCode.NEWLINE) { - // Get semicolon - let semI = bufI - 5; - if (chunk[semI] !== CharCode.SEMICOLON) { - semI += 1 | (1 + ~(chunk[semI - 1] === CharCode.SEMICOLON)); - } - - // Add the station's name to the trie and get leaf - [trie, leaf] = add(trie, chunk, minI, semI); - - // Update next entry's min - minI = bufI + 1; - - // Get temperature - const temp = parseDouble(chunk, semI + 1, bufI); - - // If the station existed - leaf += TrieNodeProto.VALUE_IDX; - if (trie[leaf] !== Trie.NULL) { - // Update the station's value - updateStation(trie[leaf], temp); - } else { - // Add the new station's value - trie[leaf] = ++stations; - newStation(stations, temp); - } + // If not newline + if (chunk[bufI] !== CharCode.NEWLINE) { + continue; + } + + // Get semicolon + let semI = bufI - 5; + if (chunk[semI] !== CharCode.SEMICOLON) { + semI += 1 | (1 + ~(chunk[semI - 1] === CharCode.SEMICOLON)); + } + + // Add the station's name to the trie and get leaf + [trie, leaf] = add(trie, chunk, minI, semI); + + // Update next entry's min + minI = bufI + 1; + + // Get temperature + const temp = parseDouble(chunk, semI + 1, bufI); + + // If the station existed + leaf += TrieNodeProto.VALUE_IDX; + if (trie[leaf] !== Trie.NULL) { + // Update the station's value + updateStation(trie[leaf], temp); + } else { + // Add the new station's value + trie[leaf] = ++stations; + newStation(stations, temp); } } @@ -79,21 +97,6 @@ export function run({ minI = 0; } - function newStation(index: number, temp: number): void { - mins[index << 3] = temp; - maxes[index << 3] = temp; - counts[index << 2] = 1; - sums[index << 1] = temp; - } - - function updateStation(index: number, temp: number): void { - index <<= 3; - mins[index] = mins[index] <= temp ? mins[index] : temp; - maxes[index] = maxes[index] >= temp ? maxes[index] : temp; - ++counts[index >> 1]; - sums[index >> 2] += temp; - } - return { id, trie }; } @@ -106,14 +109,13 @@ export function merge({ mins, sums, }: MergeRequest): MergeResponse { - function mergeStations(ai: number, bi: number): void { + const ids = mergeLeft(tries, a, b, (ai: number, bi: number): void => { ai <<= 3; bi <<= 3; mins[ai] = mins[ai] <= mins[bi] ? mins[ai] : mins[bi]; - maxes[ai] = mins[ai] >= mins[bi] ? mins[ai] : mins[bi]; + maxes[ai] = maxes[ai] >= maxes[bi] ? maxes[ai] : maxes[bi]; counts[ai >> 1] += counts[bi >> 1]; sums[ai >> 2] += sums[bi >> 2]; - } - const ids = mergeLeft(tries, a, b, mergeStations); + }); return { ids, tries }; } From a716e878d2e4d7200f97e2a673c22e1a205a662f Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Mon, 27 May 2024 20:41:16 -0400 Subject: [PATCH 63/69] Refactor worker again --- src/main/nodejs/havelessbemore/dist/index.mjs | 4 +- .../nodejs/havelessbemore/dist/index.mjs.map | 6 +- .../havelessbemore/src/constants/config.ts | 17 ++- src/main/nodejs/havelessbemore/src/main.ts | 34 ++--- .../src/types/processRequest.ts | 9 +- .../nodejs/havelessbemore/src/utils/stream.ts | 101 ++++++-------- src/main/nodejs/havelessbemore/src/worker.ts | 124 +++++++++++------- 7 files changed, 146 insertions(+), 149 deletions(-) diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index c7c69d8..d4cfa73 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -1,3 +1,3 @@ -import{availableParallelism as Y}from"node:os";import{fileURLToPath as Q}from"node:url";import{isMainThread as $,parentPort as g}from"node:worker_threads";import{closeSync as x,createWriteStream as F,openSync as G}from"node:fs";import{stdout as K}from"node:process";import{fstatSync as B,readSync as v}from"fs";function X(e,r,t){return e>r?e<=t?e:t:r}function b(e,r,t,m=0){let s=B(e).size,f=Math.max(m,Math.floor(s/r)),I=Buffer.allocUnsafe(t),i=[],o=0;for(let u=f;u=0&&ce.length&&(e=T(e,f+218)),e[0]+=218,e[s+0]=f,e[f+0]=e[1]),s=f}return[e,s]}function N(e=0,r=655360){r=Math.max(219,r);let t=new Int32Array(new SharedArrayBuffer(r<<2));return t[0]=219,t[1]=e,t}function T(e,r=0){let t=e[0];r=Math.max(r,Math.ceil(t*1.618033988749895));let m=new Int32Array(new SharedArrayBuffer(r<<2));for(let s=0;se[o].length&&(e[o]=T(e[o],l+2),s.push(o)),e[o][0]+=2,e[o][u+0]=l,e[o][l+0]=h,e[o][l+1]=a;else{let n=e[o][l+0];o!==n&&(l=e[o][l+1]),f.push([n,l,h,a])}}u+=1,c+=1}}f.splice(0,I)}while(f.length>0);return s}function O(e,r,t,m,s="",f){let I=new Array(r.length+1);I[0]=[t,3,0];let i=0,o=!1;do{let[u,M,c]=I[i];if(c>=216){--i;continue}I[i][1]+=1,++I[i][2];let p=e[u][M+0];if(p===0)continue;let _=e[u][p+0];u!==_&&(p=e[u][p+1],u=_),r[i]=c+32,I[++i]=[u,p+2,0];let a=e[u][p+1];a!==0&&(o&&m.write(s),o=!0,f(m,r,i,a))}while(i>=0)}import{Worker as Z}from"node:worker_threads";function C(e){let r=new Z(e);return r.on("error",t=>{throw t}),r.on("messageerror",t=>{throw t}),r.on("exit",t=>{if(t>1||t<0)throw new Error(`Worker ${r.threadId} exited with code ${t}`)}),r}function d(e,r){return new Promise(t=>{e.once("message",t),e.postMessage(r)})}async function P(e,r,t,m=""){t=X(t,1,512);let s=G(e,"r"),f=b(s,t,107,16384);t=f.length;let I=new SharedArrayBuffer(1e4*t+1<<4),i=new Int16Array(I),o=new Int16Array(I,2),u=new Uint32Array(I,4),M=new Float64Array(I,8),c=new Array(t),p=[],_=new Array(t);for(let n=0;n{let D=E.id;for(c[D]=E.trie;p.length>0;){let y=await d(R,{type:1,a:D,b:p.pop(),counts:u,maxes:o,mins:i,sums:M,tries:c});for(let A of y.ids)c[A]=y.tries[A]}return p.push(D),R.terminate()})}await Promise.all(_),x(s);let a=F(m,{fd:m.length<1?K.fd:void 0,flags:"a",highWaterMark:1048576}),h=Buffer.allocUnsafe(100);a.write("{"),O(c,h,p[0],a,", ",l),a.end(`} -`);function l(n,R,E,D){let y=Math.round(M[D<<1]/u[D<<2]);n.write(R.toString("utf8",0,E)),n.write("="),n.write((i[D<<3]/10).toFixed(1)),n.write("/"),n.write((y/10).toFixed(1)),n.write("/"),n.write((o[D<<3]/10).toFixed(1))}}import{readSync as V}from"fs";var U=11*48,q=111*48;function H(e,r,t){return e[r]===45?(++r,r+4>t?U-10*e[r]-e[r+2]:q-100*e[r]-10*e[r+1]-e[r+3]):r+4>t?10*e[r]+e[r+2]-U:100*e[r]+10*e[r+1]+e[r+3]-q}function W({end:e,fd:r,id:t,start:m,counts:s,maxes:f,mins:I,sums:i}){let o=(n,R)=>{I[n<<3]=R,f[n<<3]=R,s[n<<2]=1,i[n<<1]=R},u=(n,R)=>{n<<=3,I[n]=I[n]<=R?I[n]:R,f[n]=f[n]>=R?f[n]:R,++s[n>>1],i[n>>2]+=R},M=w(e-m),c=Buffer.allocUnsafe(M+107),p=0,_=0,a=0,h=t*1e4,l=N(t);for(;m{o<<=3,u<<=3,f[o]=f[o]<=f[u]?f[o]:f[u],s[o]=s[o]>=s[u]?s[o]:s[u],m[o>>1]+=m[u>>1],I[o>>2]+=I[u>>2]}),tries:t}}if($){let e=Q(import.meta.url);P(process.argv[2],e,Y())}else g.addListener("message",e=>{if(e.type===0)g.postMessage(W(e));else if(e.type===1)g.postMessage(k(e));else throw new Error("Unknown message type")}); +import{availableParallelism as J}from"node:os";import{fileURLToPath as z}from"node:url";import{isMainThread as ee,parentPort as L}from"node:worker_threads";import{closeSync as V,createWriteStream as G,fstatSync as Q,openSync as $}from"node:fs";import{stdout as j}from"node:process";function A(e,r,t){return e>r?e<=t?e:t:r}function S(e){return e*=.00625,e=Math.round(Math.log2(e)),e=2**e,A(e,16384,8388608)}function T(e,r){return Math.max(16384,Math.ceil(e/r))}function O(e,r,t){for(;--t>=0;)if(e[t]===r)return t;return-1}function U(e,r,t,a){let f=1;for(;te.length&&(e=P(e,I+218)),e[0]+=218,e[f+0]=I,e[I+0]=e[1]),f=I}return[e,f]}function C(e=0,r=655360){r=Math.max(219,r);let t=new Int32Array(new SharedArrayBuffer(r<<2));return t[0]=219,t[1]=e,t}function P(e,r=0){let t=e[0];r=Math.max(r,Math.ceil(t*1.618033988749895));let a=new Int32Array(new SharedArrayBuffer(r<<2));for(let f=0;fe[n].length&&(e[n]=P(e[n],s+2),f.push(n)),e[n][0]+=2,e[n][u+0]=s,e[n][s+0]=o,e[n][s+1]=c;else{let l=e[n][s+0];n!==l&&(s=e[n][s+1]),I.push([l,s,o,c])}}u+=1,R+=1}}I.splice(0,m)}while(I.length>0);return f}function B(e,r,t,a,f="",I){let m=new Array(r.length+1);m[0]=[t,3,0];let i=0,n=!1;do{let[u,_,R]=m[i];if(R>=216){--i;continue}m[i][1]+=1,++m[i][2];let p=e[u][_+0];if(p===0)continue;let E=e[u][p+0];u!==E&&(p=e[u][p+1],u=E),r[i]=R+32,m[++i]=[u,p+2,0];let c=e[u][p+1];c!==0&&(n&&a.write(f),n=!0,I(a,r,i,c))}while(i>=0)}import{Worker as Y}from"node:worker_threads";function H(e){let r=new Y(e);return r.on("error",t=>{throw t}),r.on("messageerror",t=>{throw t}),r.on("exit",t=>{if(t>1||t<0)throw new Error(`Worker ${r.threadId} exited with code ${t}`)}),r}function b(e,r){return new Promise(t=>{e.once("message",t),e.postMessage(r)})}async function k(e,r,t,a=""){t=A(t,1,512);let f=$(e,"r"),m=Q(f).size,i=T(m,t),n=S(i),u=new SharedArrayBuffer(1e4*t+1<<4),_=new Uint32Array(u,0,1),R=new Int16Array(u),p=new Int16Array(u,2),E=new Uint32Array(u,4),c=new Float64Array(u,8),o=new Array(t),s=[],l=new Array(t);for(let M=0;M{let y=d.id;for(o[y]=d.trie;s.length>0;){let N=await b(D,{type:1,a:y,b:s.pop(),counts:E,maxes:p,mins:R,sums:c,tries:o});for(let w of N.ids)o[w]=N.tries[w]}return s.push(y),D.terminate()})}await Promise.all(l),V(f);let X=G(a,{fd:a.length<1?j.fd:void 0,flags:"a",highWaterMark:1048576}),h=Buffer.allocUnsafe(100);X.write("{"),B(o,h,s[0],X,", ",g),X.end(`} +`);function g(M,D,d,y){let N=Math.round(c[y<<1]/E[y<<2]);M.write(D.toString("utf8",0,d)),M.write("="),M.write((R[y<<3]/10).toFixed(1)),M.write("/"),M.write((N/10).toFixed(1)),M.write("/"),M.write((p[y<<3]/10).toFixed(1))}}import{readSync as x}from"fs";var Z=11*48,W=111*48;function v(e,r,t){return e[r]===45?(++r,r+4>t?Z-10*e[r]-e[r+2]:W-100*e[r]-10*e[r+1]-e[r+3]):r+4>t?10*e[r]+e[r+2]-Z:100*e[r]+10*e[r+1]+e[r+3]-W}function F({id:e,fd:r,fileSize:t,pageSize:a,chunkSize:f,counts:I,maxes:m,mins:i,page:n,sums:u}){let _=(o,s)=>{i[o<<3]=s,m[o<<3]=s,I[o<<2]=1,u[o<<1]=s},R=(o,s)=>{o<<=3,i[o]=i[o]<=s?i[o]:s,m[o]=m[o]>=s?m[o]:s,++I[o>>1],u[o>>2]+=s},p=Buffer.allocUnsafe(f+107),E=e*1e4,c=C(e);for(;;){let o=a*Atomics.add(n,0,1);if(o>=t)break;let s=Math.min(t,o+a);o>0&&(o-=107,x(r,p,0,107,o),o+=1+O(p,10,107));let l=0,X=0,h=0;for(;o{n<<=3,u<<=3,I[n]=I[n]<=I[u]?I[n]:I[u],f[n]=f[n]>=f[u]?f[n]:f[u],a[n>>1]+=a[u>>1],m[n>>2]+=m[u>>2]}),tries:t}}if(ee){let e=z(import.meta.url);k(process.argv[2],e,J())}else L.addListener("message",e=>{if(e.type===0)L.postMessage(F(e));else if(e.type===1)L.postMessage(K(e));else throw new Error("Unknown message type")}); //# sourceMappingURL=index.mjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index 4b9a027..495c5cd 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../src/index.ts", "../src/main.ts", "../src/utils/stream.ts", "../src/utils/utf8Trie.ts", "../src/utils/worker.ts", "../src/worker.ts", "../src/utils/parse.ts"], - "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport { RequestType, type Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", (msg: Request) => {\n if (msg.type === RequestType.PROCESS) {\n parentPort!.postMessage(runWorker(msg as ProcessRequest));\n } else if (msg.type === RequestType.MERGE) {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { closeSync, createWriteStream, openSync, WriteStream } from \"node:fs\";\nimport { stdout } from \"node:process\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { clamp, getFileChunks } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\nimport { RequestType } from \"./types/request\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Open the given file\n const fd = openSync(filePath, \"r\");\n\n // Split the file into chunks. Creates 1 or fewer chunks per worker\n const chunks = getFileChunks(\n fd,\n maxWorkers,\n BRC.MAX_ENTRY_LEN,\n Config.HIGH_WATER_MARK_MIN,\n );\n\n // Adjust the number of workers to the number of chunks\n maxWorkers = chunks.length;\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: RequestType.PROCESS,\n counts,\n end: chunks[i][1],\n fd,\n id: i,\n maxes,\n mins,\n start: chunks[i][0],\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[a] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: RequestType.MERGE,\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Close the file\n closeSync(fd);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? stdout.fd : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { fstatSync, readSync } from \"fs\";\nimport { Config } from \"../constants/config\";\nimport { CharCode } from \"../constants/utf8\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Splits a file into `target` chunks or less.\n *\n * - Each chunk is aligned to a file line;\n * i.e. file start, newline ('\\n') or file end.\n * - A chunk's size will be greater than or equal to `fileSize / target`.\n * - `target` chunks or less will be generated.\n *\n * @param filePath - The local path to the file to be chunked.\n * @param target - The target number of chunks to split the file into.\n * @param maxLineLength - The maximum length of a line in the file.\n * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`.\n *\n * @returns A promise that resolves to an array of index pairs, where each\n * pair represents a chunk's start (inclusive) and end (exclusive) indices.\n *\n * @throws Will throw an error if the file cannot be opened or read.\n */\nexport function getFileChunks(\n fd: number,\n target: number,\n maxLineLength: number,\n minSize = 0,\n): [number, number][] {\n // Get the file's size\n const size = fstatSync(fd).size;\n // Calculate each chunk's target size\n const chunkSize = Math.max(minSize, Math.floor(size / target));\n // Initialize constants\n const buffer = Buffer.allocUnsafe(maxLineLength);\n const chunks: [number, number][] = [];\n // Traverse the file, visiting each chunk's end index (exclusive)\n let start = 0;\n for (let end = chunkSize; end < size; end += chunkSize) {\n // Read a line at the intended end index\n const bytesRead = readSync(fd, buffer, 0, maxLineLength, end);\n // Find the nearest newline ('\\n') character\n const newline = buffer.indexOf(CharCode.NEWLINE);\n // If found\n if (newline >= 0 && newline < bytesRead) {\n // Align end with the newline\n end += newline + 1;\n // Add the chunk\n chunks.push([start, end]);\n // Update the start index for the next chunk\n start = end;\n }\n }\n // Add the last chunk, if necessary\n if (start < size) {\n chunks.push([start, size]);\n }\n // Return chunks\n return chunks;\n}\n\n/**\n * Calculates an optimal highWaterMark value based on the given size.\n *\n * @param size - The size based on which the highWaterMark will be calculated.\n *\n * @returns The calculated highWaterMark value.\n */\nexport function getHighWaterMark(size: number): number {\n // Get size percentage\n size *= Config.HIGH_WATER_MARK_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, Config.HIGH_WATER_MARK_MIN, Config.HIGH_WATER_MARK_MAX);\n}\n", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown: number[] = [];\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.push(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return grown;\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"node:worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { readSync } from \"fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { getHighWaterMark } from \"./utils/stream\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\n\nexport function run({\n end,\n fd,\n id,\n start,\n // Shared memory\n counts,\n maxes,\n mins,\n sums,\n}: ProcessRequest): ProcessResponse {\n const newStation = (index: number, temp: number): void => {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n };\n\n const updateStation = (index: number, temp: number): void => {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n };\n\n // Initialize constants\n const chunkSize = getHighWaterMark(end - start);\n const chunk = Buffer.allocUnsafe(chunkSize + BRC.MAX_ENTRY_LEN);\n\n // Initialize variables\n let bufI = 0;\n let leaf = 0;\n let minI = 0;\n let stations = id * BRC.MAX_STATIONS;\n let trie = createTrie(id);\n\n // For each chunk\n while (start < end) {\n // Read the chunk into memory\n const bytesRead = Math.min(chunkSize, end - start);\n readSync(fd, chunk, bufI, bytesRead, start);\n start += bytesRead;\n\n // For each byte\n for (const N = bufI + bytesRead; bufI < N; ++bufI) {\n // If not newline\n if (chunk[bufI] !== CharCode.NEWLINE) {\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 5;\n if (chunk[semI] !== CharCode.SEMICOLON) {\n semI += 1 | (1 + ~(chunk[semI - 1] === CharCode.SEMICOLON));\n }\n\n // Add the station's name to the trie and get leaf\n [trie, leaf] = add(trie, chunk, minI, semI);\n\n // Update next entry's min\n minI = bufI + 1;\n\n // Get temperature\n const temp = parseDouble(chunk, semI + 1, bufI);\n\n // If the station existed\n leaf += TrieNodeProto.VALUE_IDX;\n if (trie[leaf] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf], temp);\n } else {\n // Add the new station's value\n trie[leaf] = ++stations;\n newStation(stations, temp);\n }\n }\n\n // Prepend any incomplete entry to the next chunk\n chunk.copyWithin(0, minI, bufI);\n\n // Update indices for the next chunk\n bufI -= minI;\n minI = 0;\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n const ids = mergeLeft(tries, a, b, (ai: number, bi: number): void => {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = mins[ai] <= mins[bi] ? mins[ai] : mins[bi];\n maxes[ai] = maxes[ai] >= maxes[bi] ? maxes[ai] : maxes[bi];\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n });\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], - "mappings": "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", - "names": ["availableParallelism", "fileURLToPath", "isMainThread", "parentPort", "closeSync", "createWriteStream", "openSync", "stdout", "fstatSync", "readSync", "clamp", "value", "min", "max", "getFileChunks", "fd", "target", "maxLineLength", "minSize", "size", "fstatSync", "chunkSize", "buffer", "chunks", "start", "end", "bytesRead", "readSync", "newline", "getHighWaterMark", "add", "trie", "key", "min", "max", "index", "child", "grow", "createTrie", "id", "size", "trie", "grow", "minSize", "length", "next", "i", "mergeLeft", "tries", "at", "bt", "mergeFn", "grown", "queue", "Q", "q", "ai", "bi", "bvi", "avi", "bn", "ri", "rt", "li", "lt", "print", "key", "trieIndex", "stream", "separator", "callbackFn", "stack", "top", "tail", "trieI", "childPtr", "numChild", "childI", "childTrieI", "valueIndex", "Worker", "createWorker", "workerPath", "worker", "err", "code", "exec", "req", "resolve", "run", "filePath", "workerPath", "maxWorkers", "outPath", "clamp", "fd", "openSync", "chunks", "getFileChunks", "valBuf", "mins", "maxes", "counts", "sums", "tries", "unmerged", "tasks", "i", "worker", "createWorker", "exec", "res", "a", "id", "closeSync", "out", "createWriteStream", "stdout", "buffer", "print", "printStation", "stream", "name", "nameLen", "vi", "avg", "readSync", "CHAR_ZERO_11", "CHAR_ZERO_111", "parseDouble", "b", "min", "max", "run", "end", "fd", "id", "start", "counts", "maxes", "mins", "sums", "newStation", "index", "temp", "updateStation", "chunkSize", "getHighWaterMark", "chunk", "bufI", "leaf", "minI", "stations", "trie", "createTrie", "bytesRead", "readSync", "N", "semI", "add", "parseDouble", "merge", "a", "b", "tries", "mergeLeft", "ai", "bi", "isMainThread", "workerPath", "fileURLToPath", "run", "availableParallelism", "parentPort", "msg", "merge"] + "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport { RequestType, type Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", (msg: Request) => {\n if (msg.type === RequestType.PROCESS) {\n parentPort!.postMessage(runWorker(msg as ProcessRequest));\n } else if (msg.type === RequestType.MERGE) {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { closeSync, createWriteStream, fstatSync, openSync, WriteStream } from \"node:fs\";\nimport { stdout } from \"node:process\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { RequestType } from \"./types/request\";\nimport { clamp, getChunkSize, getPageSize } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Open the given file\n const fd = openSync(filePath, \"r\");\n\n // Get file stats\n const fstats = fstatSync(fd);\n const fileSize = fstats.size;\n const pageSize = getPageSize(fileSize, maxWorkers);\n const chunkSize = getChunkSize(pageSize);\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const page = new Uint32Array(valBuf, 0, 1);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: RequestType.PROCESS,\n id: i,\n // I/O\n fd,\n fileSize,\n pageSize,\n chunkSize,\n // Shared memory\n counts,\n maxes,\n mins,\n page,\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[a] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: RequestType.MERGE,\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Close the file\n closeSync(fd);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? stdout.fd : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { Config } from \"../constants/config\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Calculates a chunk size based on a given page size.\n *\n * @param size - The page size.\n *\n * @returns The calculated chunk size.\n */\nexport function getChunkSize(size: number): number {\n // Get size percentage\n size *= Config.CHUNK_SIZE_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, Config.CHUNK_SIZE_MIN, Config.CHUNK_SIZE_MAX);\n}\n\n/**\n * Calculates a page size based on a given file size.\n *\n * @param fileSize - The file size.\n * @param workers - The number of workers the file will be split across.\n *\n * @returns The calculated page size.\n */\nexport function getPageSize(fileSize: number, workers: number): number {\n return Math.max(Config.CHUNK_SIZE_MIN, Math.ceil(fileSize / workers));\n}\n\n/**\n * Returns the index of the last occurrence of a \n * specified value in an array, or `-1` if it's not present.\n * \n * @param array - The array to search through.\n * @param searchElement \u2014 The value to locate in the array.\n * @param max \u2014 The array index at which to begin searching backward.\n * \n * @returns the index of the last occurrence, or `-1` if it's not present.\n */\nexport function lastIndexOf(array: ArrayLike, searchElement: T, max: number): number {\n while (--max >= 0) {\n if (array[max] === searchElement) {\n return max;\n }\n }\n return -1;\n}", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown: number[] = [];\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.push(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return grown;\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"node:worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { readSync } from \"fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { lastIndexOf } from \"./utils/stream\";\n\nexport function run({\n id,\n // I/O\n fd,\n fileSize,\n pageSize,\n chunkSize,\n // Shared memory\n counts,\n maxes,\n mins,\n page,\n sums,\n}: ProcessRequest): ProcessResponse {\n const newStation = (index: number, temp: number): void => {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n };\n\n const updateStation = (index: number, temp: number): void => {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n };\n\n // Initialize constants\n const chunk = Buffer.allocUnsafe(chunkSize + BRC.MAX_ENTRY_LEN);\n let stations = id * BRC.MAX_STATIONS;\n let trie = createTrie(id);\n\n // For each page\n while (true) {\n\n // Get page start\n let start = pageSize * Atomics.add(page, 0, 1);\n if (start >= fileSize) {\n break;\n }\n\n // Get page end\n const end = Math.min(fileSize, start + pageSize);\n\n // Align start with entry\n if (start > 0) {\n start -= BRC.MAX_ENTRY_LEN;\n readSync(fd, chunk, 0, BRC.MAX_ENTRY_LEN, start);\n start += 1 + lastIndexOf(chunk, CharCode.NEWLINE, BRC.MAX_ENTRY_LEN);\n }\n \n // Initialize variables\n let bufI = 0;\n let leaf = 0;\n let minI = 0;\n\n // For each chunk\n while (start < end) {\n // Read the chunk into memory\n const bytesRead = Math.min(chunkSize, end - start);\n readSync(fd, chunk, bufI, bytesRead, start);\n start += bytesRead;\n\n // For each byte\n for (const N = bufI + bytesRead; bufI < N; ++bufI) {\n // If not newline\n if (chunk[bufI] !== CharCode.NEWLINE) {\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 5;\n if (chunk[semI] !== CharCode.SEMICOLON) {\n semI += 1 | (1 + ~(chunk[semI - 1] === CharCode.SEMICOLON));\n }\n\n // Add the station's name to the trie and get leaf\n [trie, leaf] = add(trie, chunk, minI, semI);\n\n // Update next entry's min\n minI = bufI + 1;\n\n // Get temperature\n const temp = parseDouble(chunk, semI + 1, bufI);\n\n // If the station existed\n leaf += TrieNodeProto.VALUE_IDX;\n if (trie[leaf] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf], temp);\n } else {\n // Add the new station's value\n trie[leaf] = ++stations;\n newStation(stations, temp);\n }\n }\n\n // Prepend any incomplete entry to the next chunk\n chunk.copyWithin(0, minI, bufI);\n\n // Update indices for the next chunk\n bufI -= minI;\n minI = 0;\n }\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n const ids = mergeLeft(tries, a, b, (ai: number, bi: number): void => {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = mins[ai] <= mins[bi] ? mins[ai] : mins[bi];\n maxes[ai] = maxes[ai] >= maxes[bi] ? maxes[ai] : maxes[bi];\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n });\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], + "mappings": "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", + "names": ["availableParallelism", "fileURLToPath", "isMainThread", "parentPort", "closeSync", "createWriteStream", "fstatSync", "openSync", "stdout", "clamp", "value", "min", "max", "getChunkSize", "size", "getPageSize", "fileSize", "workers", "lastIndexOf", "array", "searchElement", "add", "trie", "key", "min", "max", "index", "child", "grow", "createTrie", "id", "size", "trie", "grow", "minSize", "length", "next", "i", "mergeLeft", "tries", "at", "bt", "mergeFn", "grown", "queue", "Q", "q", "ai", "bi", "bvi", "avi", "bn", "ri", "rt", "li", "lt", "print", "key", "trieIndex", "stream", "separator", "callbackFn", "stack", "top", "tail", "trieI", "childPtr", "numChild", "childI", "childTrieI", "valueIndex", "Worker", "createWorker", "workerPath", "worker", "err", "code", "exec", "req", "resolve", "run", "filePath", "workerPath", "maxWorkers", "outPath", "clamp", "fd", "openSync", "fileSize", "fstatSync", "pageSize", "getPageSize", "chunkSize", "getChunkSize", "valBuf", "page", "mins", "maxes", "counts", "sums", "tries", "unmerged", "tasks", "i", "worker", "createWorker", "exec", "res", "a", "id", "closeSync", "out", "createWriteStream", "stdout", "buffer", "print", "printStation", "stream", "name", "nameLen", "vi", "avg", "readSync", "CHAR_ZERO_11", "CHAR_ZERO_111", "parseDouble", "b", "min", "max", "run", "id", "fd", "fileSize", "pageSize", "chunkSize", "counts", "maxes", "mins", "page", "sums", "newStation", "index", "temp", "updateStation", "chunk", "stations", "trie", "createTrie", "start", "end", "readSync", "lastIndexOf", "bufI", "leaf", "minI", "bytesRead", "N", "semI", "add", "parseDouble", "merge", "a", "b", "tries", "mergeLeft", "ai", "bi", "isMainThread", "workerPath", "fileURLToPath", "run", "availableParallelism", "parentPort", "msg", "merge"] } diff --git a/src/main/nodejs/havelessbemore/src/constants/config.ts b/src/main/nodejs/havelessbemore/src/constants/config.ts index 7f6ccab..a50aa50 100644 --- a/src/main/nodejs/havelessbemore/src/constants/config.ts +++ b/src/main/nodejs/havelessbemore/src/constants/config.ts @@ -2,25 +2,24 @@ export const enum Config { /** - * The minimum value in bytes for `highWaterMark`. + * The minimum value in bytes for a chunk size. */ - HIGH_WATER_MARK_MIN = 16384, // 16 KiB + CHUNK_SIZE_MIN = 16384, // 16 KiB /** - * The maximum value in bytes for `highWaterMark`. + * The maximum value in bytes for a chunk size. */ - HIGH_WATER_MARK_MAX = 8388608, // 8 MiB + CHUNK_SIZE_MAX = 8388608, // 8 MiB /** - * The `highWaterMark` for write streams. + * The ratio of the page size for calculating chunk size. */ - HIGH_WATER_MARK_OUT = 1048576, // 1 MiB + CHUNK_SIZE_RATIO = 0.00625, /** - * The ratio of the file size to use for calculating - * the `highWaterMark` of a stream. + * The `highWaterMark` for write streams. */ - HIGH_WATER_MARK_RATIO = 0.00625, + HIGH_WATER_MARK_OUT = 1048576, // 1 MiB /** * The minimum number of web workers (inclusive). diff --git a/src/main/nodejs/havelessbemore/src/main.ts b/src/main/nodejs/havelessbemore/src/main.ts index 004ebab..2d34df2 100644 --- a/src/main/nodejs/havelessbemore/src/main.ts +++ b/src/main/nodejs/havelessbemore/src/main.ts @@ -1,4 +1,4 @@ -import { closeSync, createWriteStream, openSync, WriteStream } from "node:fs"; +import { closeSync, createWriteStream, fstatSync, openSync, WriteStream } from "node:fs"; import { stdout } from "node:process"; import type { MergeRequest } from "./types/mergeRequest"; @@ -8,10 +8,10 @@ import type { ProcessResponse } from "./types/processResponse"; import { BRC } from "./constants/brc"; import { Config } from "./constants/config"; -import { clamp, getFileChunks } from "./utils/stream"; +import { RequestType } from "./types/request"; +import { clamp, getChunkSize, getPageSize } from "./utils/stream"; import { print } from "./utils/utf8Trie"; import { createWorker, exec } from "./utils/worker"; -import { RequestType } from "./types/request"; export async function run( filePath: string, @@ -25,21 +25,17 @@ export async function run( // Open the given file const fd = openSync(filePath, "r"); - // Split the file into chunks. Creates 1 or fewer chunks per worker - const chunks = getFileChunks( - fd, - maxWorkers, - BRC.MAX_ENTRY_LEN, - Config.HIGH_WATER_MARK_MIN, - ); - - // Adjust the number of workers to the number of chunks - maxWorkers = chunks.length; + // Get file stats + const fstats = fstatSync(fd); + const fileSize = fstats.size; + const pageSize = getPageSize(fileSize, maxWorkers); + const chunkSize = getChunkSize(pageSize); // Initialize data const valBuf = new SharedArrayBuffer( (BRC.MAX_STATIONS * maxWorkers + 1) << 4, ); + const page = new Uint32Array(valBuf, 0, 1); const mins = new Int16Array(valBuf); const maxes = new Int16Array(valBuf, 2); const counts = new Uint32Array(valBuf, 4); @@ -55,13 +51,17 @@ export async function run( // Process the chunk tasks[i] = exec(worker, { type: RequestType.PROCESS, - counts, - end: chunks[i][1], - fd, id: i, + // I/O + fd, + fileSize, + pageSize, + chunkSize, + // Shared memory + counts, maxes, mins, - start: chunks[i][0], + page, sums, }).then(async (res) => { // Add result to trie array diff --git a/src/main/nodejs/havelessbemore/src/types/processRequest.ts b/src/main/nodejs/havelessbemore/src/types/processRequest.ts index 7936108..cb08cda 100644 --- a/src/main/nodejs/havelessbemore/src/types/processRequest.ts +++ b/src/main/nodejs/havelessbemore/src/types/processRequest.ts @@ -2,13 +2,16 @@ import { Request, RequestType } from "./request"; export interface ProcessRequest extends Request { type: RequestType.PROCESS; - end: number; - fd: number; id: number; - start: number; + // I/O + fd: number; + fileSize: number; + pageSize: number; + chunkSize: number; // Shared memory counts: Uint32Array; maxes: Int16Array; mins: Int16Array; + page: Uint32Array; sums: Float64Array; } diff --git a/src/main/nodejs/havelessbemore/src/utils/stream.ts b/src/main/nodejs/havelessbemore/src/utils/stream.ts index 00ea135..b44e9c7 100644 --- a/src/main/nodejs/havelessbemore/src/utils/stream.ts +++ b/src/main/nodejs/havelessbemore/src/utils/stream.ts @@ -1,6 +1,4 @@ -import { fstatSync, readSync } from "fs"; import { Config } from "../constants/config"; -import { CharCode } from "../constants/utf8"; /** * Clamp a value within a given range. @@ -16,75 +14,50 @@ export function clamp(value: number, min: number, max: number): number { } /** - * Splits a file into `target` chunks or less. + * Calculates a chunk size based on a given page size. * - * - Each chunk is aligned to a file line; - * i.e. file start, newline ('\n') or file end. - * - A chunk's size will be greater than or equal to `fileSize / target`. - * - `target` chunks or less will be generated. + * @param size - The page size. * - * @param filePath - The local path to the file to be chunked. - * @param target - The target number of chunks to split the file into. - * @param maxLineLength - The maximum length of a line in the file. - * @param minSize - The minimum size of a chunk in bytes. Defaults to `0`. - * - * @returns A promise that resolves to an array of index pairs, where each - * pair represents a chunk's start (inclusive) and end (exclusive) indices. - * - * @throws Will throw an error if the file cannot be opened or read. - */ -export function getFileChunks( - fd: number, - target: number, - maxLineLength: number, - minSize = 0, -): [number, number][] { - // Get the file's size - const size = fstatSync(fd).size; - // Calculate each chunk's target size - const chunkSize = Math.max(minSize, Math.floor(size / target)); - // Initialize constants - const buffer = Buffer.allocUnsafe(maxLineLength); - const chunks: [number, number][] = []; - // Traverse the file, visiting each chunk's end index (exclusive) - let start = 0; - for (let end = chunkSize; end < size; end += chunkSize) { - // Read a line at the intended end index - const bytesRead = readSync(fd, buffer, 0, maxLineLength, end); - // Find the nearest newline ('\n') character - const newline = buffer.indexOf(CharCode.NEWLINE); - // If found - if (newline >= 0 && newline < bytesRead) { - // Align end with the newline - end += newline + 1; - // Add the chunk - chunks.push([start, end]); - // Update the start index for the next chunk - start = end; - } - } - // Add the last chunk, if necessary - if (start < size) { - chunks.push([start, size]); - } - // Return chunks - return chunks; -} - -/** - * Calculates an optimal highWaterMark value based on the given size. - * - * @param size - The size based on which the highWaterMark will be calculated. - * - * @returns The calculated highWaterMark value. + * @returns The calculated chunk size. */ -export function getHighWaterMark(size: number): number { +export function getChunkSize(size: number): number { // Get size percentage - size *= Config.HIGH_WATER_MARK_RATIO; + size *= Config.CHUNK_SIZE_RATIO; // Get nearest power size = Math.round(Math.log2(size)); // Calculate high water mark size = 2 ** size; // Clamp value - return clamp(size, Config.HIGH_WATER_MARK_MIN, Config.HIGH_WATER_MARK_MAX); + return clamp(size, Config.CHUNK_SIZE_MIN, Config.CHUNK_SIZE_MAX); } + +/** + * Calculates a page size based on a given file size. + * + * @param fileSize - The file size. + * @param workers - The number of workers the file will be split across. + * + * @returns The calculated page size. + */ +export function getPageSize(fileSize: number, workers: number): number { + return Math.max(Config.CHUNK_SIZE_MIN, Math.ceil(fileSize / workers)); +} + +/** + * Returns the index of the last occurrence of a + * specified value in an array, or `-1` if it's not present. + * + * @param array - The array to search through. + * @param searchElement — The value to locate in the array. + * @param max — The array index at which to begin searching backward. + * + * @returns the index of the last occurrence, or `-1` if it's not present. + */ +export function lastIndexOf(array: ArrayLike, searchElement: T, max: number): number { + while (--max >= 0) { + if (array[max] === searchElement) { + return max; + } + } + return -1; +} \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/src/worker.ts b/src/main/nodejs/havelessbemore/src/worker.ts index d71b648..49b22f1 100644 --- a/src/main/nodejs/havelessbemore/src/worker.ts +++ b/src/main/nodejs/havelessbemore/src/worker.ts @@ -8,18 +8,21 @@ import type { ProcessResponse } from "./types/processResponse"; import { BRC } from "./constants/brc"; import { CharCode, Trie, TrieNodeProto } from "./constants/utf8"; import { parseDouble } from "./utils/parse"; -import { getHighWaterMark } from "./utils/stream"; import { add, createTrie, mergeLeft } from "./utils/utf8Trie"; +import { lastIndexOf } from "./utils/stream"; export function run({ - end, - fd, id, - start, + // I/O + fd, + fileSize, + pageSize, + chunkSize, // Shared memory counts, maxes, mins, + page, sums, }: ProcessRequest): ProcessResponse { const newStation = (index: number, temp: number): void => { @@ -38,63 +41,82 @@ export function run({ }; // Initialize constants - const chunkSize = getHighWaterMark(end - start); const chunk = Buffer.allocUnsafe(chunkSize + BRC.MAX_ENTRY_LEN); - - // Initialize variables - let bufI = 0; - let leaf = 0; - let minI = 0; let stations = id * BRC.MAX_STATIONS; let trie = createTrie(id); - // For each chunk - while (start < end) { - // Read the chunk into memory - const bytesRead = Math.min(chunkSize, end - start); - readSync(fd, chunk, bufI, bytesRead, start); - start += bytesRead; - - // For each byte - for (const N = bufI + bytesRead; bufI < N; ++bufI) { - // If not newline - if (chunk[bufI] !== CharCode.NEWLINE) { - continue; - } - - // Get semicolon - let semI = bufI - 5; - if (chunk[semI] !== CharCode.SEMICOLON) { - semI += 1 | (1 + ~(chunk[semI - 1] === CharCode.SEMICOLON)); - } + // For each page + while (true) { - // Add the station's name to the trie and get leaf - [trie, leaf] = add(trie, chunk, minI, semI); - - // Update next entry's min - minI = bufI + 1; + // Get page start + let start = pageSize * Atomics.add(page, 0, 1); + if (start >= fileSize) { + break; + } - // Get temperature - const temp = parseDouble(chunk, semI + 1, bufI); + // Get page end + const end = Math.min(fileSize, start + pageSize); - // If the station existed - leaf += TrieNodeProto.VALUE_IDX; - if (trie[leaf] !== Trie.NULL) { - // Update the station's value - updateStation(trie[leaf], temp); - } else { - // Add the new station's value - trie[leaf] = ++stations; - newStation(stations, temp); - } + // Align start with entry + if (start > 0) { + start -= BRC.MAX_ENTRY_LEN; + readSync(fd, chunk, 0, BRC.MAX_ENTRY_LEN, start); + start += 1 + lastIndexOf(chunk, CharCode.NEWLINE, BRC.MAX_ENTRY_LEN); } + + // Initialize variables + let bufI = 0; + let leaf = 0; + let minI = 0; + + // For each chunk + while (start < end) { + // Read the chunk into memory + const bytesRead = Math.min(chunkSize, end - start); + readSync(fd, chunk, bufI, bytesRead, start); + start += bytesRead; + + // For each byte + for (const N = bufI + bytesRead; bufI < N; ++bufI) { + // If not newline + if (chunk[bufI] !== CharCode.NEWLINE) { + continue; + } + + // Get semicolon + let semI = bufI - 5; + if (chunk[semI] !== CharCode.SEMICOLON) { + semI += 1 | (1 + ~(chunk[semI - 1] === CharCode.SEMICOLON)); + } + + // Add the station's name to the trie and get leaf + [trie, leaf] = add(trie, chunk, minI, semI); + + // Update next entry's min + minI = bufI + 1; + + // Get temperature + const temp = parseDouble(chunk, semI + 1, bufI); + + // If the station existed + leaf += TrieNodeProto.VALUE_IDX; + if (trie[leaf] !== Trie.NULL) { + // Update the station's value + updateStation(trie[leaf], temp); + } else { + // Add the new station's value + trie[leaf] = ++stations; + newStation(stations, temp); + } + } - // Prepend any incomplete entry to the next chunk - chunk.copyWithin(0, minI, bufI); + // Prepend any incomplete entry to the next chunk + chunk.copyWithin(0, minI, bufI); - // Update indices for the next chunk - bufI -= minI; - minI = 0; + // Update indices for the next chunk + bufI -= minI; + minI = 0; + } } return { id, trie }; From b92c185a17a4c94b2331996ac646c6ece6d424de Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Mon, 27 May 2024 23:29:03 -0400 Subject: [PATCH 64/69] Refactor worker hot loop --- src/main/nodejs/havelessbemore/dist/index.mjs | 4 ++-- .../nodejs/havelessbemore/dist/index.mjs.map | 6 +++--- src/main/nodejs/havelessbemore/src/worker.ts | 17 ++++++----------- 3 files changed, 11 insertions(+), 16 deletions(-) diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index d4cfa73..456a5e4 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -1,3 +1,3 @@ -import{availableParallelism as J}from"node:os";import{fileURLToPath as z}from"node:url";import{isMainThread as ee,parentPort as L}from"node:worker_threads";import{closeSync as V,createWriteStream as G,fstatSync as Q,openSync as $}from"node:fs";import{stdout as j}from"node:process";function A(e,r,t){return e>r?e<=t?e:t:r}function S(e){return e*=.00625,e=Math.round(Math.log2(e)),e=2**e,A(e,16384,8388608)}function T(e,r){return Math.max(16384,Math.ceil(e/r))}function O(e,r,t){for(;--t>=0;)if(e[t]===r)return t;return-1}function U(e,r,t,a){let f=1;for(;te.length&&(e=P(e,I+218)),e[0]+=218,e[f+0]=I,e[I+0]=e[1]),f=I}return[e,f]}function C(e=0,r=655360){r=Math.max(219,r);let t=new Int32Array(new SharedArrayBuffer(r<<2));return t[0]=219,t[1]=e,t}function P(e,r=0){let t=e[0];r=Math.max(r,Math.ceil(t*1.618033988749895));let a=new Int32Array(new SharedArrayBuffer(r<<2));for(let f=0;fe[n].length&&(e[n]=P(e[n],s+2),f.push(n)),e[n][0]+=2,e[n][u+0]=s,e[n][s+0]=o,e[n][s+1]=c;else{let l=e[n][s+0];n!==l&&(s=e[n][s+1]),I.push([l,s,o,c])}}u+=1,R+=1}}I.splice(0,m)}while(I.length>0);return f}function B(e,r,t,a,f="",I){let m=new Array(r.length+1);m[0]=[t,3,0];let i=0,n=!1;do{let[u,_,R]=m[i];if(R>=216){--i;continue}m[i][1]+=1,++m[i][2];let p=e[u][_+0];if(p===0)continue;let E=e[u][p+0];u!==E&&(p=e[u][p+1],u=E),r[i]=R+32,m[++i]=[u,p+2,0];let c=e[u][p+1];c!==0&&(n&&a.write(f),n=!0,I(a,r,i,c))}while(i>=0)}import{Worker as Y}from"node:worker_threads";function H(e){let r=new Y(e);return r.on("error",t=>{throw t}),r.on("messageerror",t=>{throw t}),r.on("exit",t=>{if(t>1||t<0)throw new Error(`Worker ${r.threadId} exited with code ${t}`)}),r}function b(e,r){return new Promise(t=>{e.once("message",t),e.postMessage(r)})}async function k(e,r,t,a=""){t=A(t,1,512);let f=$(e,"r"),m=Q(f).size,i=T(m,t),n=S(i),u=new SharedArrayBuffer(1e4*t+1<<4),_=new Uint32Array(u,0,1),R=new Int16Array(u),p=new Int16Array(u,2),E=new Uint32Array(u,4),c=new Float64Array(u,8),o=new Array(t),s=[],l=new Array(t);for(let M=0;M{let y=d.id;for(o[y]=d.trie;s.length>0;){let N=await b(D,{type:1,a:y,b:s.pop(),counts:E,maxes:p,mins:R,sums:c,tries:o});for(let w of N.ids)o[w]=N.tries[w]}return s.push(y),D.terminate()})}await Promise.all(l),V(f);let X=G(a,{fd:a.length<1?j.fd:void 0,flags:"a",highWaterMark:1048576}),h=Buffer.allocUnsafe(100);X.write("{"),B(o,h,s[0],X,", ",g),X.end(`} -`);function g(M,D,d,y){let N=Math.round(c[y<<1]/E[y<<2]);M.write(D.toString("utf8",0,d)),M.write("="),M.write((R[y<<3]/10).toFixed(1)),M.write("/"),M.write((N/10).toFixed(1)),M.write("/"),M.write((p[y<<3]/10).toFixed(1))}}import{readSync as x}from"fs";var Z=11*48,W=111*48;function v(e,r,t){return e[r]===45?(++r,r+4>t?Z-10*e[r]-e[r+2]:W-100*e[r]-10*e[r+1]-e[r+3]):r+4>t?10*e[r]+e[r+2]-Z:100*e[r]+10*e[r+1]+e[r+3]-W}function F({id:e,fd:r,fileSize:t,pageSize:a,chunkSize:f,counts:I,maxes:m,mins:i,page:n,sums:u}){let _=(o,s)=>{i[o<<3]=s,m[o<<3]=s,I[o<<2]=1,u[o<<1]=s},R=(o,s)=>{o<<=3,i[o]=i[o]<=s?i[o]:s,m[o]=m[o]>=s?m[o]:s,++I[o>>1],u[o>>2]+=s},p=Buffer.allocUnsafe(f+107),E=e*1e4,c=C(e);for(;;){let o=a*Atomics.add(n,0,1);if(o>=t)break;let s=Math.min(t,o+a);o>0&&(o-=107,x(r,p,0,107,o),o+=1+O(p,10,107));let l=0,X=0,h=0;for(;o{n<<=3,u<<=3,I[n]=I[n]<=I[u]?I[n]:I[u],f[n]=f[n]>=f[u]?f[n]:f[u],a[n>>1]+=a[u>>1],m[n>>2]+=m[u>>2]}),tries:t}}if(ee){let e=z(import.meta.url);k(process.argv[2],e,J())}else L.addListener("message",e=>{if(e.type===0)L.postMessage(F(e));else if(e.type===1)L.postMessage(K(e));else throw new Error("Unknown message type")}); +import{availableParallelism as J}from"node:os";import{fileURLToPath as z}from"node:url";import{isMainThread as ee,parentPort as L}from"node:worker_threads";import{closeSync as V,createWriteStream as G,fstatSync as Q,openSync as $}from"node:fs";import{stdout as j}from"node:process";function A(e,r,t){return e>r?e<=t?e:t:r}function S(e){return e*=.00625,e=Math.round(Math.log2(e)),e=2**e,A(e,16384,8388608)}function T(e,r){return Math.max(16384,Math.ceil(e/r))}function O(e,r,t){for(;--t>=0;)if(e[t]===r)return t;return-1}function U(e,r,t,a){let s=1;for(;te.length&&(e=P(e,I+218)),e[0]+=218,e[s+0]=I,e[I+0]=e[1]),s=I}return[e,s]}function C(e=0,r=655360){r=Math.max(219,r);let t=new Int32Array(new SharedArrayBuffer(r<<2));return t[0]=219,t[1]=e,t}function P(e,r=0){let t=e[0];r=Math.max(r,Math.ceil(t*1.618033988749895));let a=new Int32Array(new SharedArrayBuffer(r<<2));for(let s=0;se[n].length&&(e[n]=P(e[n],f+2),s.push(n)),e[n][0]+=2,e[n][u+0]=f,e[n][f+0]=o,e[n][f+1]=c;else{let R=e[n][f+0];n!==R&&(f=e[n][f+1]),I.push([R,f,o,c])}}u+=1,M+=1}}I.splice(0,m)}while(I.length>0);return s}function B(e,r,t,a,s="",I){let m=new Array(r.length+1);m[0]=[t,3,0];let i=0,n=!1;do{let[u,_,M]=m[i];if(M>=216){--i;continue}m[i][1]+=1,++m[i][2];let p=e[u][_+0];if(p===0)continue;let E=e[u][p+0];u!==E&&(p=e[u][p+1],u=E),r[i]=M+32,m[++i]=[u,p+2,0];let c=e[u][p+1];c!==0&&(n&&a.write(s),n=!0,I(a,r,i,c))}while(i>=0)}import{Worker as Y}from"node:worker_threads";function H(e){let r=new Y(e);return r.on("error",t=>{throw t}),r.on("messageerror",t=>{throw t}),r.on("exit",t=>{if(t>1||t<0)throw new Error(`Worker ${r.threadId} exited with code ${t}`)}),r}function b(e,r){return new Promise(t=>{e.once("message",t),e.postMessage(r)})}async function Z(e,r,t,a=""){t=A(t,1,512);let s=$(e,"r"),m=Q(s).size,i=T(m,t),n=S(i),u=new SharedArrayBuffer(1e4*t+1<<4),_=new Uint32Array(u,0,1),M=new Int16Array(u),p=new Int16Array(u,2),E=new Uint32Array(u,4),c=new Float64Array(u,8),o=new Array(t),f=[],R=new Array(t);for(let l=0;l{let X=h.id;for(o[X]=h.trie;f.length>0;){let N=await b(D,{type:1,a:X,b:f.pop(),counts:E,maxes:p,mins:M,sums:c,tries:o});for(let w of N.ids)o[w]=N.tries[w]}return f.push(X),D.terminate()})}await Promise.all(R),V(s);let y=G(a,{fd:a.length<1?j.fd:void 0,flags:"a",highWaterMark:1048576}),d=Buffer.allocUnsafe(100);y.write("{"),B(o,d,f[0],y,", ",g),y.end(`} +`);function g(l,D,h,X){let N=Math.round(c[X<<1]/E[X<<2]);l.write(D.toString("utf8",0,h)),l.write("="),l.write((M[X<<3]/10).toFixed(1)),l.write("/"),l.write((N/10).toFixed(1)),l.write("/"),l.write((p[X<<3]/10).toFixed(1))}}import{readSync as v}from"fs";var k=11*48,W=111*48;function x(e,r,t){return e[r]===45?(++r,r+4>t?k-10*e[r]-e[r+2]:W-100*e[r]-10*e[r+1]-e[r+3]):r+4>t?10*e[r]+e[r+2]-k:100*e[r]+10*e[r+1]+e[r+3]-W}function F({id:e,fd:r,fileSize:t,pageSize:a,chunkSize:s,counts:I,maxes:m,mins:i,page:n,sums:u}){let _=(o,f)=>{i[o<<3]=f,m[o<<3]=f,I[o<<2]=1,u[o<<1]=f},M=(o,f)=>{o<<=3,i[o]=i[o]<=f?i[o]:f,m[o]=m[o]>=f?m[o]:f,++I[o>>1],u[o>>2]+=f},p=Buffer.allocUnsafe(s+107),E=e*1e4,c=C(e);for(;;){let o=a*Atomics.add(n,0,1);if(o>=t)break;let f=Math.min(t,o+a);o>0&&(o-=107,v(r,p,0,107,o),o+=1+O(p,10,107));for(let R=0;o{n<<=3,u<<=3,I[n]=I[n]<=I[u]?I[n]:I[u],s[n]=s[n]>=s[u]?s[n]:s[u],a[n>>1]+=a[u>>1],m[n>>2]+=m[u>>2]}),tries:t}}if(ee){let e=z(import.meta.url);Z(process.argv[2],e,J())}else L.addListener("message",e=>{if(e.type===0)L.postMessage(F(e));else if(e.type===1)L.postMessage(K(e));else throw new Error("Unknown message type")}); //# sourceMappingURL=index.mjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index 495c5cd..05973a0 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../src/index.ts", "../src/main.ts", "../src/utils/stream.ts", "../src/utils/utf8Trie.ts", "../src/utils/worker.ts", "../src/worker.ts", "../src/utils/parse.ts"], - "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport { RequestType, type Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", (msg: Request) => {\n if (msg.type === RequestType.PROCESS) {\n parentPort!.postMessage(runWorker(msg as ProcessRequest));\n } else if (msg.type === RequestType.MERGE) {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { closeSync, createWriteStream, fstatSync, openSync, WriteStream } from \"node:fs\";\nimport { stdout } from \"node:process\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { RequestType } from \"./types/request\";\nimport { clamp, getChunkSize, getPageSize } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Open the given file\n const fd = openSync(filePath, \"r\");\n\n // Get file stats\n const fstats = fstatSync(fd);\n const fileSize = fstats.size;\n const pageSize = getPageSize(fileSize, maxWorkers);\n const chunkSize = getChunkSize(pageSize);\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const page = new Uint32Array(valBuf, 0, 1);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: RequestType.PROCESS,\n id: i,\n // I/O\n fd,\n fileSize,\n pageSize,\n chunkSize,\n // Shared memory\n counts,\n maxes,\n mins,\n page,\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[a] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: RequestType.MERGE,\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Close the file\n closeSync(fd);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? stdout.fd : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { Config } from \"../constants/config\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Calculates a chunk size based on a given page size.\n *\n * @param size - The page size.\n *\n * @returns The calculated chunk size.\n */\nexport function getChunkSize(size: number): number {\n // Get size percentage\n size *= Config.CHUNK_SIZE_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, Config.CHUNK_SIZE_MIN, Config.CHUNK_SIZE_MAX);\n}\n\n/**\n * Calculates a page size based on a given file size.\n *\n * @param fileSize - The file size.\n * @param workers - The number of workers the file will be split across.\n *\n * @returns The calculated page size.\n */\nexport function getPageSize(fileSize: number, workers: number): number {\n return Math.max(Config.CHUNK_SIZE_MIN, Math.ceil(fileSize / workers));\n}\n\n/**\n * Returns the index of the last occurrence of a \n * specified value in an array, or `-1` if it's not present.\n * \n * @param array - The array to search through.\n * @param searchElement \u2014 The value to locate in the array.\n * @param max \u2014 The array index at which to begin searching backward.\n * \n * @returns the index of the last occurrence, or `-1` if it's not present.\n */\nexport function lastIndexOf(array: ArrayLike, searchElement: T, max: number): number {\n while (--max >= 0) {\n if (array[max] === searchElement) {\n return max;\n }\n }\n return -1;\n}", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown: number[] = [];\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.push(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return grown;\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"node:worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { readSync } from \"fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { lastIndexOf } from \"./utils/stream\";\n\nexport function run({\n id,\n // I/O\n fd,\n fileSize,\n pageSize,\n chunkSize,\n // Shared memory\n counts,\n maxes,\n mins,\n page,\n sums,\n}: ProcessRequest): ProcessResponse {\n const newStation = (index: number, temp: number): void => {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n };\n\n const updateStation = (index: number, temp: number): void => {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n };\n\n // Initialize constants\n const chunk = Buffer.allocUnsafe(chunkSize + BRC.MAX_ENTRY_LEN);\n let stations = id * BRC.MAX_STATIONS;\n let trie = createTrie(id);\n\n // For each page\n while (true) {\n\n // Get page start\n let start = pageSize * Atomics.add(page, 0, 1);\n if (start >= fileSize) {\n break;\n }\n\n // Get page end\n const end = Math.min(fileSize, start + pageSize);\n\n // Align start with entry\n if (start > 0) {\n start -= BRC.MAX_ENTRY_LEN;\n readSync(fd, chunk, 0, BRC.MAX_ENTRY_LEN, start);\n start += 1 + lastIndexOf(chunk, CharCode.NEWLINE, BRC.MAX_ENTRY_LEN);\n }\n \n // Initialize variables\n let bufI = 0;\n let leaf = 0;\n let minI = 0;\n\n // For each chunk\n while (start < end) {\n // Read the chunk into memory\n const bytesRead = Math.min(chunkSize, end - start);\n readSync(fd, chunk, bufI, bytesRead, start);\n start += bytesRead;\n\n // For each byte\n for (const N = bufI + bytesRead; bufI < N; ++bufI) {\n // If not newline\n if (chunk[bufI] !== CharCode.NEWLINE) {\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 5;\n if (chunk[semI] !== CharCode.SEMICOLON) {\n semI += 1 | (1 + ~(chunk[semI - 1] === CharCode.SEMICOLON));\n }\n\n // Add the station's name to the trie and get leaf\n [trie, leaf] = add(trie, chunk, minI, semI);\n\n // Update next entry's min\n minI = bufI + 1;\n\n // Get temperature\n const temp = parseDouble(chunk, semI + 1, bufI);\n\n // If the station existed\n leaf += TrieNodeProto.VALUE_IDX;\n if (trie[leaf] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf], temp);\n } else {\n // Add the new station's value\n trie[leaf] = ++stations;\n newStation(stations, temp);\n }\n }\n\n // Prepend any incomplete entry to the next chunk\n chunk.copyWithin(0, minI, bufI);\n\n // Update indices for the next chunk\n bufI -= minI;\n minI = 0;\n }\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n const ids = mergeLeft(tries, a, b, (ai: number, bi: number): void => {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = mins[ai] <= mins[bi] ? mins[ai] : mins[bi];\n maxes[ai] = maxes[ai] >= maxes[bi] ? maxes[ai] : maxes[bi];\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n });\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], - "mappings": "AAAA,OAAS,wBAAAA,MAA4B,UACrC,OAAS,iBAAAC,MAAqB,WAC9B,OAAS,gBAAAC,GAAc,cAAAC,MAAkB,sBCFzC,OAAS,aAAAC,EAAW,qBAAAC,EAAmB,aAAAC,EAAW,YAAAC,MAA6B,UAC/E,OAAS,UAAAC,MAAc,eCUhB,SAASC,EAAMC,EAAeC,EAAaC,EAAqB,CACrE,OAAOF,EAAQC,EAAOD,GAASE,EAAMF,EAAQE,EAAOD,CACtD,CASO,SAASE,EAAaC,EAAsB,CAEjD,OAAAA,GAAQ,OAERA,EAAO,KAAK,MAAM,KAAK,KAAKA,CAAI,CAAC,EAEjCA,EAAO,GAAKA,EAELL,EAAMK,eAAkD,CACjE,CAUO,SAASC,EAAYC,EAAkBC,EAAyB,CACrE,OAAO,KAAK,UAA2B,KAAK,KAAKD,EAAWC,CAAO,CAAC,CACtE,CAYO,SAASC,EAAeC,EAAqBC,EAAkBR,EAAqB,CACzF,KAAO,EAAEA,GAAO,GACd,GAAIO,EAAMP,CAAG,IAAMQ,EACjB,OAAOR,EAGX,MAAO,EACT,CCnDO,SAASS,EACdC,EACAC,EACAC,EACAC,EACsB,CACtB,IAAIC,IACJ,KAAOF,EAAMC,GAAK,CAChBC,GACE,EACA,GAAwBH,EAAIC,GAAK,EAAI,IACvC,IAAIG,EAAQL,EAAKI,EAAQ,CAAwB,EAC7CC,IAAU,IAEZA,EAAQL,GAAuB,EAC3BK,EAAQ,IAAoBL,EAAK,SACnCA,EAAOM,EAAKN,EAAMK,EAAQ,GAAiB,GAE7CL,GAAuB,GAAK,IAE5BA,EAAKI,EAAQ,CAAwB,EAAIC,EAEzCL,EAAKK,EAAQ,CAAoB,EAAIL,GAAqB,GAE5DI,EAAQC,CACV,CAEA,MAAO,CAACL,EAAMI,CAAK,CACrB,CA8BO,SAASG,EAAWC,EAAK,EAAGC,SAAsC,CACvEA,EAAO,KAAK,QAAmBA,CAAI,EACnC,IAAMC,EAAO,IAAI,WAAW,IAAI,kBAAkBD,GAAQ,CAAC,CAAC,EAC5D,OAAAC,GAAuB,EAAI,IAC3BA,GAAqB,EAAIF,EAClBE,CACT,CAEO,SAASC,EAAKD,EAAkBE,EAAU,EAAe,CAC9D,IAAMC,EAASH,GAAuB,EACtCE,EAAU,KAAK,IAAIA,EAAS,KAAK,KAAKC,EAAS,iBAAkB,CAAC,EAClE,IAAMC,EAAO,IAAI,WAAW,IAAI,kBAAkBF,GAAW,CAAC,CAAC,EAC/D,QAASG,EAAI,EAAGA,EAAIF,EAAQ,EAAEE,EAC5BD,EAAKC,CAAC,EAAIL,EAAKK,CAAC,EAElB,OAAOD,CACT,CAEO,SAASE,EACdC,EACAC,EACAC,EACAC,EACU,CACV,IAAMC,EAAkB,CAAC,EACnBC,EAA4C,CAChD,CAACJ,IAAwBC,GAAsB,CACjD,EAEA,EAAG,CACD,IAAMI,EAAID,EAAM,OAChB,QAASE,EAAI,EAAGA,EAAID,EAAG,EAAEC,EAAG,CAE1B,GAAI,CAACN,EAAIO,EAAIN,EAAIO,CAAE,EAAIJ,EAAME,CAAC,EAGxBG,EAAMV,EAAME,CAAE,EAAEO,EAAK,CAAuB,EAClD,GAAIC,IAAQ,EAAW,CAErB,IAAMC,EAAMX,EAAMC,CAAE,EAAEO,EAAK,CAAuB,EAC9CG,IAAQ,EACVR,EAAQQ,EAAKD,CAAG,EAEhBV,EAAMC,CAAE,EAAEO,EAAK,CAAuB,EAAIE,CAE9C,CAGAF,GAAM,EACNC,GAAM,EAGN,IAAMG,EAAKH,EAAK,IAChB,KAAOA,EAAKG,GAAI,CAEd,IAAIC,EAAKb,EAAME,CAAE,EAAEO,EAAK,CAAwB,EAChD,GAAII,IAAO,EAAW,CAEpB,IAAMC,EAAKd,EAAME,CAAE,EAAEW,EAAK,CAAoB,EAC1CX,IAAOY,IACTD,EAAKb,EAAME,CAAE,EAAEW,EAAK,CAAyB,GAI/C,IAAIE,EAAKf,EAAMC,CAAE,EAAEO,EAAK,CAAwB,EAChD,GAAIO,IAAO,EAETA,EAAKf,EAAMC,CAAE,GAAoB,EAC7Bc,EAAK,EAAwBf,EAAMC,CAAE,EAAE,SACzCD,EAAMC,CAAE,EAAIP,EAAKM,EAAMC,CAAE,EAAGc,EAAK,CAAqB,EACtDX,EAAM,KAAKH,CAAE,GAEfD,EAAMC,CAAE,GAAoB,GAAK,EAEjCD,EAAMC,CAAE,EAAEO,EAAK,CAAwB,EAAIO,EAE3Cf,EAAMC,CAAE,EAAEc,EAAK,CAAwB,EAAID,EAC3Cd,EAAMC,CAAE,EAAEc,EAAK,CAAyB,EAAIF,MACvC,CAEL,IAAMG,EAAKhB,EAAMC,CAAE,EAAEc,EAAK,CAAoB,EAC1Cd,IAAOe,IACTD,EAAKf,EAAMC,CAAE,EAAEc,EAAK,CAAyB,GAG/CV,EAAM,KAAK,CAACW,EAAID,EAAID,EAAID,CAAE,CAAC,CAC7B,CACF,CAGAL,GAAM,EACNC,GAAM,CACR,CACF,CACAJ,EAAM,OAAO,EAAGC,CAAC,CACnB,OAASD,EAAM,OAAS,GACxB,OAAOD,CACT,CAEO,SAASa,EACdjB,EACAkB,EACAC,EACAC,EACAC,EAAY,GACZC,EAMM,CACN,IAAMC,EAAQ,IAAI,MAAgCL,EAAI,OAAS,CAAC,EAChEK,EAAM,CAAC,EAAI,CAACJ,EAAW,EAAiD,CAAC,EAEzE,IAAIK,EAAM,EACNC,EAAO,GACX,EAAG,CAED,GAAI,CAACC,EAAOC,EAAUC,CAAQ,EAAIL,EAAMC,CAAG,EAG3C,GAAII,GAAY,IAA4B,CAC1C,EAAEJ,EACF,QACF,CAGAD,EAAMC,CAAG,EAAE,CAAC,GAAK,EACjB,EAAED,EAAMC,CAAG,EAAE,CAAC,EAGd,IAAIK,EAAS7B,EAAM0B,CAAK,EAAEC,EAAW,CAAwB,EAC7D,GAAIE,IAAW,EACb,SAIF,IAAMC,EAAa9B,EAAM0B,CAAK,EAAEG,EAAS,CAAoB,EACzDH,IAAUI,IACZD,EAAS7B,EAAM0B,CAAK,EAAEG,EAAS,CAAyB,EACxDH,EAAQI,GAIVZ,EAAIM,CAAG,EAAII,EAAW,GACtBL,EAAM,EAAEC,CAAG,EAAI,CAACE,EAAOG,EAAS,EAA4B,CAAC,EAG7D,IAAME,EAAa/B,EAAM0B,CAAK,EAAEG,EAAS,CAAuB,EAC5DE,IAAe,IAEbN,GACFL,EAAO,MAAMC,CAAS,EAExBI,EAAO,GACPH,EAAWF,EAAQF,EAAKM,EAAKO,CAAU,EAE3C,OAASP,GAAO,EAClB,CCpOA,OAAS,UAAAQ,MAAc,sBAShB,SAASC,EAAaC,EAA4B,CACvD,IAAMC,EAAS,IAAIH,EAAOE,CAAU,EACpC,OAAAC,EAAO,GAAG,QAAUC,GAAQ,CAC1B,MAAMA,CACR,CAAC,EACDD,EAAO,GAAG,eAAiBC,GAAQ,CACjC,MAAMA,CACR,CAAC,EACDD,EAAO,GAAG,OAASE,GAAS,CAC1B,GAAIA,EAAO,GAAKA,EAAO,EACrB,MAAM,IAAI,MAAM,UAAUF,EAAO,QAAQ,qBAAqBE,CAAI,EAAE,CAExE,CAAC,EACMF,CACT,CAUO,SAASG,EAAeH,EAAgBI,EAAwB,CACrE,OAAO,IAAI,QAAcC,GAAY,CACnCL,EAAO,KAAK,UAAWK,CAAO,EAC9BL,EAAO,YAAYI,CAAG,CACxB,CAAC,CACH,CHvBA,eAAsBE,EACpBC,EACAC,EACAC,EACAC,EAAU,GACK,CAEfD,EAAaE,EAAMF,OAAkD,EAGrE,IAAMG,EAAKC,EAASN,EAAU,GAAG,EAI3BO,EADSC,EAAUH,CAAE,EACH,KAClBI,EAAWC,EAAYH,EAAUL,CAAU,EAC3CS,EAAYC,EAAaH,CAAQ,EAGjCI,EAAS,IAAI,kBAChB,IAAmBX,EAAa,GAAM,CACzC,EACMY,EAAO,IAAI,YAAYD,EAAQ,EAAG,CAAC,EACnCE,EAAO,IAAI,WAAWF,CAAM,EAC5BG,EAAQ,IAAI,WAAWH,EAAQ,CAAC,EAChCI,EAAS,IAAI,YAAYJ,EAAQ,CAAC,EAClCK,EAAO,IAAI,aAAaL,EAAQ,CAAC,EACjCM,EAAQ,IAAI,MAAkBjB,CAAU,EAGxCkB,EAAqB,CAAC,EACtBC,EAAQ,IAAI,MAAwBnB,CAAU,EACpD,QAASoB,EAAI,EAAGA,EAAIpB,EAAY,EAAEoB,EAAG,CAEnC,IAAMC,EAASC,EAAavB,CAAU,EAEtCoB,EAAMC,CAAC,EAAIG,EAAsCF,EAAQ,CACvD,OACA,GAAID,EAEJ,GAAAjB,EACA,SAAAE,EACA,SAAAE,EACA,UAAAE,EAEA,OAAAM,EACA,MAAAD,EACA,KAAAD,EACA,KAAAD,EACA,KAAAI,CACF,CAAC,EAAE,KAAK,MAAOQ,GAAQ,CAErB,IAAMC,EAAID,EAAI,GAGd,IAFAP,EAAMQ,CAAC,EAAID,EAAI,KAERN,EAAS,OAAS,GAAG,CAC1B,IAAMM,EAAM,MAAMD,EAAkCF,EAAQ,CAC1D,OACA,EAAAI,EACA,EAAGP,EAAS,IAAI,EAChB,OAAAH,EACA,MAAAD,EACA,KAAAD,EACA,KAAAG,EACA,MAAAC,CACF,CAAC,EAED,QAAWS,KAAMF,EAAI,IACnBP,EAAMS,CAAE,EAAIF,EAAI,MAAME,CAAE,CAE5B,CACA,OAAAR,EAAS,KAAKO,CAAC,EAERJ,EAAO,UAAU,CAC1B,CAAC,CACH,CAGA,MAAM,QAAQ,IAAIF,CAAK,EAGvBQ,EAAUxB,CAAE,EAGZ,IAAMyB,EAAMC,EAAkB5B,EAAS,CACrC,GAAIA,EAAQ,OAAS,EAAI6B,EAAO,GAAK,OACrC,MAAO,IACP,qBACF,CAAC,EACKC,EAAS,OAAO,eAAoC,EAC1DH,EAAI,MAAM,GAAG,EACbI,EAAMf,EAAOc,EAAQb,EAAS,CAAC,EAAGU,EAAK,KAAMK,CAAY,EACzDL,EAAI,IAAI;AAAA,CAAK,EAEb,SAASK,EACPC,EACAC,EACAC,EACAC,EACM,CACN,IAAMC,EAAM,KAAK,MAAMtB,EAAKqB,GAAM,CAAC,EAAItB,EAAOsB,GAAM,CAAC,CAAC,EACtDH,EAAO,MAAMC,EAAK,SAAS,OAAQ,EAAGC,CAAO,CAAC,EAC9CF,EAAO,MAAM,GAAG,EAChBA,EAAO,OAAOrB,EAAKwB,GAAM,CAAC,EAAI,IAAI,QAAQ,CAAC,CAAC,EAC5CH,EAAO,MAAM,GAAG,EAChBA,EAAO,OAAOI,EAAM,IAAI,QAAQ,CAAC,CAAC,EAClCJ,EAAO,MAAM,GAAG,EAChBA,EAAO,OAAOpB,EAAMuB,GAAM,CAAC,EAAI,IAAI,QAAQ,CAAC,CAAC,CAC/C,CACF,CI5HA,OAAS,YAAAE,MAAgB,KCElB,IAAMC,EAAe,GAAK,GACpBC,EAAgB,IAAM,GAO5B,SAASC,EAAYC,EAAWC,EAAaC,EAAqB,CACvE,OAAIF,EAAEC,CAAG,IAAM,IACb,EAAEA,EACKA,EAAM,EAAIC,EACbL,EAAe,GAAKG,EAAEC,CAAG,EAAID,EAAEC,EAAM,CAAC,EACtCH,EAAgB,IAAME,EAAEC,CAAG,EAAI,GAAKD,EAAEC,EAAM,CAAC,EAAID,EAAEC,EAAM,CAAC,GAEzDA,EAAM,EAAIC,EACb,GAAKF,EAAEC,CAAG,EAAID,EAAEC,EAAM,CAAC,EAAIJ,EAC3B,IAAMG,EAAEC,CAAG,EAAI,GAAKD,EAAEC,EAAM,CAAC,EAAID,EAAEC,EAAM,CAAC,EAAIH,CACpD,CDPO,SAASK,EAAI,CAClB,GAAAC,EAEA,GAAAC,EACA,SAAAC,EACA,SAAAC,EACA,UAAAC,EAEA,OAAAC,EACA,MAAAC,EACA,KAAAC,EACA,KAAAC,EACA,KAAAC,CACF,EAAoC,CAClC,IAAMC,EAAa,CAACC,EAAeC,IAAuB,CACxDL,EAAKI,GAAS,CAAC,EAAIC,EACnBN,EAAMK,GAAS,CAAC,EAAIC,EACpBP,EAAOM,GAAS,CAAC,EAAI,EACrBF,EAAKE,GAAS,CAAC,EAAIC,CACrB,EAEMC,EAAgB,CAACF,EAAeC,IAAuB,CAC3DD,IAAU,EACVJ,EAAKI,CAAK,EAAIJ,EAAKI,CAAK,GAAKC,EAAOL,EAAKI,CAAK,EAAIC,EAClDN,EAAMK,CAAK,EAAIL,EAAMK,CAAK,GAAKC,EAAON,EAAMK,CAAK,EAAIC,EACrD,EAAEP,EAAOM,GAAS,CAAC,EACnBF,EAAKE,GAAS,CAAC,GAAKC,CACtB,EAGME,EAAQ,OAAO,YAAYV,EAAY,GAAiB,EAC1DW,EAAWf,EAAK,IAChBgB,EAAOC,EAAWjB,CAAE,EAGxB,OAAa,CAGX,IAAIkB,EAAQf,EAAW,QAAQ,IAAIK,EAAM,EAAG,CAAC,EAC7C,GAAIU,GAAShB,EACX,MAIF,IAAMiB,EAAM,KAAK,IAAIjB,EAAUgB,EAAQf,CAAQ,EAG3Ce,EAAQ,IACVA,GAAS,IACTE,EAASnB,EAAIa,EAAO,MAAsBI,CAAK,EAC/CA,GAAS,EAAIG,EAAYP,QAA0C,GAIrE,IAAIQ,EAAO,EACPC,EAAO,EACPC,EAAO,EAGX,KAAON,EAAQC,GAAK,CAElB,IAAMM,EAAY,KAAK,IAAIrB,EAAWe,EAAMD,CAAK,EACjDE,EAASnB,EAAIa,EAAOQ,EAAMG,EAAWP,CAAK,EAC1CA,GAASO,EAGT,QAAWC,EAAIJ,EAAOG,EAAWH,EAAOI,EAAG,EAAEJ,EAAM,CAEjD,GAAIR,EAAMQ,CAAI,IAAM,GAClB,SAIF,IAAIK,EAAOL,EAAO,EACdR,EAAMa,CAAI,IAAM,KAClBA,GAAQ,EAAK,EAAI,EAAEb,EAAMa,EAAO,CAAC,IAAM,KAIzC,CAACX,EAAMO,CAAI,EAAIK,EAAIZ,EAAMF,EAAOU,EAAMG,CAAI,EAG1CH,EAAOF,EAAO,EAGd,IAAMV,EAAOiB,EAAYf,EAAOa,EAAO,EAAGL,CAAI,EAG9CC,GAAQ,EACJP,EAAKO,CAAI,IAAM,EAEjBV,EAAcG,EAAKO,CAAI,EAAGX,CAAI,GAG9BI,EAAKO,CAAI,EAAI,EAAER,EACfL,EAAWK,EAAUH,CAAI,EAE7B,CAGAE,EAAM,WAAW,EAAGU,EAAMF,CAAI,EAG9BA,GAAQE,EACRA,EAAO,CACT,CACF,CAEA,MAAO,CAAE,GAAAxB,EAAI,KAAAgB,CAAK,CACpB,CAEO,SAASc,EAAM,CACpB,EAAAC,EACA,EAAAC,EACA,MAAAC,EACA,OAAA5B,EACA,MAAAC,EACA,KAAAC,EACA,KAAAE,CACF,EAAgC,CAS9B,MAAO,CAAE,IARGyB,EAAUD,EAAOF,EAAGC,EAAG,CAACG,EAAYC,IAAqB,CACnED,IAAO,EACPC,IAAO,EACP7B,EAAK4B,CAAE,EAAI5B,EAAK4B,CAAE,GAAK5B,EAAK6B,CAAE,EAAI7B,EAAK4B,CAAE,EAAI5B,EAAK6B,CAAE,EACpD9B,EAAM6B,CAAE,EAAI7B,EAAM6B,CAAE,GAAK7B,EAAM8B,CAAE,EAAI9B,EAAM6B,CAAE,EAAI7B,EAAM8B,CAAE,EACzD/B,EAAO8B,GAAM,CAAC,GAAK9B,EAAO+B,GAAM,CAAC,EACjC3B,EAAK0B,GAAM,CAAC,GAAK1B,EAAK2B,GAAM,CAAC,CAC/B,CAAC,EACa,MAAAH,CAAM,CACtB,CLnIA,GAAII,GAAc,CAChB,IAAMC,EAAaC,EAAc,YAAY,GAAG,EAChDC,EAAQ,QAAQ,KAAK,CAAC,EAAGF,EAAYG,EAAqB,CAAC,CAC7D,MACEC,EAAY,YAAY,UAAYC,GAAiB,CACnD,GAAIA,EAAI,OAAS,EACfD,EAAY,YAAYF,EAAUG,CAAqB,CAAC,UAC/CA,EAAI,OAAS,EACtBD,EAAY,YAAYE,EAAMD,CAAmB,CAAC,MAElD,OAAM,IAAI,MAAM,sBAAsB,CAE1C,CAAC", - "names": ["availableParallelism", "fileURLToPath", "isMainThread", "parentPort", "closeSync", "createWriteStream", "fstatSync", "openSync", "stdout", "clamp", "value", "min", "max", "getChunkSize", "size", "getPageSize", "fileSize", "workers", "lastIndexOf", "array", "searchElement", "add", "trie", "key", "min", "max", "index", "child", "grow", "createTrie", "id", "size", "trie", "grow", "minSize", "length", "next", "i", "mergeLeft", "tries", "at", "bt", "mergeFn", "grown", "queue", "Q", "q", "ai", "bi", "bvi", "avi", "bn", "ri", "rt", "li", "lt", "print", "key", "trieIndex", "stream", "separator", "callbackFn", "stack", "top", "tail", "trieI", "childPtr", "numChild", "childI", "childTrieI", "valueIndex", "Worker", "createWorker", "workerPath", "worker", "err", "code", "exec", "req", "resolve", "run", "filePath", "workerPath", "maxWorkers", "outPath", "clamp", "fd", "openSync", "fileSize", "fstatSync", "pageSize", "getPageSize", "chunkSize", "getChunkSize", "valBuf", "page", "mins", "maxes", "counts", "sums", "tries", "unmerged", "tasks", "i", "worker", "createWorker", "exec", "res", "a", "id", "closeSync", "out", "createWriteStream", "stdout", "buffer", "print", "printStation", "stream", "name", "nameLen", "vi", "avg", "readSync", "CHAR_ZERO_11", "CHAR_ZERO_111", "parseDouble", "b", "min", "max", "run", "id", "fd", "fileSize", "pageSize", "chunkSize", "counts", "maxes", "mins", "page", "sums", "newStation", "index", "temp", "updateStation", "chunk", "stations", "trie", "createTrie", "start", "end", "readSync", "lastIndexOf", "bufI", "leaf", "minI", "bytesRead", "N", "semI", "add", "parseDouble", "merge", "a", "b", "tries", "mergeLeft", "ai", "bi", "isMainThread", "workerPath", "fileURLToPath", "run", "availableParallelism", "parentPort", "msg", "merge"] + "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport { RequestType, type Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", (msg: Request) => {\n if (msg.type === RequestType.PROCESS) {\n parentPort!.postMessage(runWorker(msg as ProcessRequest));\n } else if (msg.type === RequestType.MERGE) {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { closeSync, createWriteStream, fstatSync, openSync, WriteStream } from \"node:fs\";\nimport { stdout } from \"node:process\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { RequestType } from \"./types/request\";\nimport { clamp, getChunkSize, getPageSize } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Open the given file\n const fd = openSync(filePath, \"r\");\n\n // Get file stats\n const fstats = fstatSync(fd);\n const fileSize = fstats.size;\n const pageSize = getPageSize(fileSize, maxWorkers);\n const chunkSize = getChunkSize(pageSize);\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const page = new Uint32Array(valBuf, 0, 1);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: RequestType.PROCESS,\n id: i,\n // I/O\n fd,\n fileSize,\n pageSize,\n chunkSize,\n // Shared memory\n counts,\n maxes,\n mins,\n page,\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[a] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: RequestType.MERGE,\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Close the file\n closeSync(fd);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? stdout.fd : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { Config } from \"../constants/config\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Calculates a chunk size based on a given page size.\n *\n * @param size - The page size.\n *\n * @returns The calculated chunk size.\n */\nexport function getChunkSize(size: number): number {\n // Get size percentage\n size *= Config.CHUNK_SIZE_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, Config.CHUNK_SIZE_MIN, Config.CHUNK_SIZE_MAX);\n}\n\n/**\n * Calculates a page size based on a given file size.\n *\n * @param fileSize - The file size.\n * @param workers - The number of workers the file will be split across.\n *\n * @returns The calculated page size.\n */\nexport function getPageSize(fileSize: number, workers: number): number {\n return Math.max(Config.CHUNK_SIZE_MIN, Math.ceil(fileSize / workers));\n}\n\n/**\n * Returns the index of the last occurrence of a \n * specified value in an array, or `-1` if it's not present.\n * \n * @param array - The array to search through.\n * @param searchElement \u2014 The value to locate in the array.\n * @param max \u2014 The array index at which to begin searching backward.\n * \n * @returns the index of the last occurrence, or `-1` if it's not present.\n */\nexport function lastIndexOf(array: ArrayLike, searchElement: T, max: number): number {\n while (--max >= 0) {\n if (array[max] === searchElement) {\n return max;\n }\n }\n return -1;\n}", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown: number[] = [];\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.push(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return grown;\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"node:worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { readSync } from \"fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { lastIndexOf } from \"./utils/stream\";\n\nexport function run({\n id,\n // I/O\n fd,\n fileSize,\n pageSize,\n chunkSize,\n // Shared memory\n counts,\n maxes,\n mins,\n page,\n sums,\n}: ProcessRequest): ProcessResponse {\n const newStation = (index: number, temp: number): void => {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n };\n\n const updateStation = (index: number, temp: number): void => {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n };\n\n // Initialize constants\n const chunk = Buffer.allocUnsafe(chunkSize + BRC.MAX_ENTRY_LEN);\n let stations = id * BRC.MAX_STATIONS;\n let trie = createTrie(id);\n\n // For each page\n while (true) {\n\n // Get page start\n let start = pageSize * Atomics.add(page, 0, 1);\n if (start >= fileSize) {\n break;\n }\n\n // Get page end\n const end = Math.min(fileSize, start + pageSize);\n\n // Align start with entry\n if (start > 0) {\n start -= BRC.MAX_ENTRY_LEN;\n readSync(fd, chunk, 0, BRC.MAX_ENTRY_LEN, start);\n start += 1 + lastIndexOf(chunk, CharCode.NEWLINE, BRC.MAX_ENTRY_LEN);\n }\n\n // For each chunk\n for (let bufI = 0; start < end; start += chunkSize) {\n // Read the chunk into memory\n let maxI = Math.min(chunkSize, end - start);\n maxI = bufI + readSync(fd, chunk, bufI, maxI, start);\n\n // For each byte\n let minI = 0;\n for (let leaf: number; bufI < maxI; ++bufI) {\n \n // If not newline\n if (chunk[bufI] !== CharCode.NEWLINE) {\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 5;\n if (chunk[semI] !== CharCode.SEMICOLON) {\n semI += 1 | (1 + ~(chunk[semI - 1] === CharCode.SEMICOLON));\n }\n\n // Add the station's name to the trie and get leaf\n [trie, leaf] = add(trie, chunk, minI, semI);\n\n // Update next entry's min\n minI = bufI + 1;\n\n // Get temperature\n const temp = parseDouble(chunk, semI + 1, bufI);\n\n // If the station existed\n leaf += TrieNodeProto.VALUE_IDX;\n if (trie[leaf] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf], temp);\n } else {\n // Add the new station's value\n trie[leaf] = ++stations;\n newStation(stations, temp);\n }\n }\n\n // Prepend any incomplete entry to the next chunk\n chunk.copyWithin(0, minI, bufI);\n\n // Update indices for the next chunk\n bufI -= minI;\n }\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n const ids = mergeLeft(tries, a, b, (ai: number, bi: number): void => {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = mins[ai] <= mins[bi] ? mins[ai] : mins[bi];\n maxes[ai] = maxes[ai] >= maxes[bi] ? maxes[ai] : maxes[bi];\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n });\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], + "mappings": "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", + "names": ["availableParallelism", "fileURLToPath", "isMainThread", "parentPort", "closeSync", "createWriteStream", "fstatSync", "openSync", "stdout", "clamp", "value", "min", "max", "getChunkSize", "size", "getPageSize", "fileSize", "workers", "lastIndexOf", "array", "searchElement", "add", "trie", "key", "min", "max", "index", "child", "grow", "createTrie", "id", "size", "trie", "grow", "minSize", "length", "next", "i", "mergeLeft", "tries", "at", "bt", "mergeFn", "grown", "queue", "Q", "q", "ai", "bi", "bvi", "avi", "bn", "ri", "rt", "li", "lt", "print", "key", "trieIndex", "stream", "separator", "callbackFn", "stack", "top", "tail", "trieI", "childPtr", "numChild", "childI", "childTrieI", "valueIndex", "Worker", "createWorker", "workerPath", "worker", "err", "code", "exec", "req", "resolve", "run", "filePath", "workerPath", "maxWorkers", "outPath", "clamp", "fd", "openSync", "fileSize", "fstatSync", "pageSize", "getPageSize", "chunkSize", "getChunkSize", "valBuf", "page", "mins", "maxes", "counts", "sums", "tries", "unmerged", "tasks", "i", "worker", "createWorker", "exec", "res", "a", "id", "closeSync", "out", "createWriteStream", "stdout", "buffer", "print", "printStation", "stream", "name", "nameLen", "vi", "avg", "readSync", "CHAR_ZERO_11", "CHAR_ZERO_111", "parseDouble", "b", "min", "max", "run", "id", "fd", "fileSize", "pageSize", "chunkSize", "counts", "maxes", "mins", "page", "sums", "newStation", "index", "temp", "updateStation", "chunk", "stations", "trie", "createTrie", "start", "end", "readSync", "lastIndexOf", "bufI", "maxI", "minI", "leaf", "semI", "add", "parseDouble", "merge", "a", "b", "tries", "mergeLeft", "ai", "bi", "isMainThread", "workerPath", "fileURLToPath", "run", "availableParallelism", "parentPort", "msg", "merge"] } diff --git a/src/main/nodejs/havelessbemore/src/worker.ts b/src/main/nodejs/havelessbemore/src/worker.ts index 49b22f1..db83929 100644 --- a/src/main/nodejs/havelessbemore/src/worker.ts +++ b/src/main/nodejs/havelessbemore/src/worker.ts @@ -63,21 +63,17 @@ export function run({ readSync(fd, chunk, 0, BRC.MAX_ENTRY_LEN, start); start += 1 + lastIndexOf(chunk, CharCode.NEWLINE, BRC.MAX_ENTRY_LEN); } - - // Initialize variables - let bufI = 0; - let leaf = 0; - let minI = 0; // For each chunk - while (start < end) { + for (let bufI = 0; start < end; start += chunkSize) { // Read the chunk into memory - const bytesRead = Math.min(chunkSize, end - start); - readSync(fd, chunk, bufI, bytesRead, start); - start += bytesRead; + let maxI = Math.min(chunkSize, end - start); + maxI = bufI + readSync(fd, chunk, bufI, maxI, start); // For each byte - for (const N = bufI + bytesRead; bufI < N; ++bufI) { + let minI = 0; + for (let leaf: number; bufI < maxI; ++bufI) { + // If not newline if (chunk[bufI] !== CharCode.NEWLINE) { continue; @@ -115,7 +111,6 @@ export function run({ // Update indices for the next chunk bufI -= minI; - minI = 0; } } From da092eb72012fd79bb12aabe6adfa6c009f4490e Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Thu, 30 May 2024 22:05:23 -0400 Subject: [PATCH 65/69] Align reads with system page size --- src/main/nodejs/havelessbemore/dist/index.mjs | 4 +-- .../nodejs/havelessbemore/dist/index.mjs.map | 6 ++-- .../nodejs/havelessbemore/esbuild.config.js | 1 - .../havelessbemore/src/constants/config.ts | 31 ++++++++++++++++--- .../nodejs/havelessbemore/src/utils/stream.ts | 15 +++++---- src/main/nodejs/havelessbemore/src/worker.ts | 30 ++++++++---------- 6 files changed, 54 insertions(+), 33 deletions(-) diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index 456a5e4..45948fd 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -1,3 +1,3 @@ -import{availableParallelism as J}from"node:os";import{fileURLToPath as z}from"node:url";import{isMainThread as ee,parentPort as L}from"node:worker_threads";import{closeSync as V,createWriteStream as G,fstatSync as Q,openSync as $}from"node:fs";import{stdout as j}from"node:process";function A(e,r,t){return e>r?e<=t?e:t:r}function S(e){return e*=.00625,e=Math.round(Math.log2(e)),e=2**e,A(e,16384,8388608)}function T(e,r){return Math.max(16384,Math.ceil(e/r))}function O(e,r,t){for(;--t>=0;)if(e[t]===r)return t;return-1}function U(e,r,t,a){let s=1;for(;te.length&&(e=P(e,I+218)),e[0]+=218,e[s+0]=I,e[I+0]=e[1]),s=I}return[e,s]}function C(e=0,r=655360){r=Math.max(219,r);let t=new Int32Array(new SharedArrayBuffer(r<<2));return t[0]=219,t[1]=e,t}function P(e,r=0){let t=e[0];r=Math.max(r,Math.ceil(t*1.618033988749895));let a=new Int32Array(new SharedArrayBuffer(r<<2));for(let s=0;se[n].length&&(e[n]=P(e[n],f+2),s.push(n)),e[n][0]+=2,e[n][u+0]=f,e[n][f+0]=o,e[n][f+1]=c;else{let R=e[n][f+0];n!==R&&(f=e[n][f+1]),I.push([R,f,o,c])}}u+=1,M+=1}}I.splice(0,m)}while(I.length>0);return s}function B(e,r,t,a,s="",I){let m=new Array(r.length+1);m[0]=[t,3,0];let i=0,n=!1;do{let[u,_,M]=m[i];if(M>=216){--i;continue}m[i][1]+=1,++m[i][2];let p=e[u][_+0];if(p===0)continue;let E=e[u][p+0];u!==E&&(p=e[u][p+1],u=E),r[i]=M+32,m[++i]=[u,p+2,0];let c=e[u][p+1];c!==0&&(n&&a.write(s),n=!0,I(a,r,i,c))}while(i>=0)}import{Worker as Y}from"node:worker_threads";function H(e){let r=new Y(e);return r.on("error",t=>{throw t}),r.on("messageerror",t=>{throw t}),r.on("exit",t=>{if(t>1||t<0)throw new Error(`Worker ${r.threadId} exited with code ${t}`)}),r}function b(e,r){return new Promise(t=>{e.once("message",t),e.postMessage(r)})}async function Z(e,r,t,a=""){t=A(t,1,512);let s=$(e,"r"),m=Q(s).size,i=T(m,t),n=S(i),u=new SharedArrayBuffer(1e4*t+1<<4),_=new Uint32Array(u,0,1),M=new Int16Array(u),p=new Int16Array(u,2),E=new Uint32Array(u,4),c=new Float64Array(u,8),o=new Array(t),f=[],R=new Array(t);for(let l=0;l{let X=h.id;for(o[X]=h.trie;f.length>0;){let N=await b(D,{type:1,a:X,b:f.pop(),counts:E,maxes:p,mins:M,sums:c,tries:o});for(let w of N.ids)o[w]=N.tries[w]}return f.push(X),D.terminate()})}await Promise.all(R),V(s);let y=G(a,{fd:a.length<1?j.fd:void 0,flags:"a",highWaterMark:1048576}),d=Buffer.allocUnsafe(100);y.write("{"),B(o,d,f[0],y,", ",g),y.end(`} -`);function g(l,D,h,X){let N=Math.round(c[X<<1]/E[X<<2]);l.write(D.toString("utf8",0,h)),l.write("="),l.write((M[X<<3]/10).toFixed(1)),l.write("/"),l.write((N/10).toFixed(1)),l.write("/"),l.write((p[X<<3]/10).toFixed(1))}}import{readSync as v}from"fs";var k=11*48,W=111*48;function x(e,r,t){return e[r]===45?(++r,r+4>t?k-10*e[r]-e[r+2]:W-100*e[r]-10*e[r+1]-e[r+3]):r+4>t?10*e[r]+e[r+2]-k:100*e[r]+10*e[r+1]+e[r+3]-W}function F({id:e,fd:r,fileSize:t,pageSize:a,chunkSize:s,counts:I,maxes:m,mins:i,page:n,sums:u}){let _=(o,f)=>{i[o<<3]=f,m[o<<3]=f,I[o<<2]=1,u[o<<1]=f},M=(o,f)=>{o<<=3,i[o]=i[o]<=f?i[o]:f,m[o]=m[o]>=f?m[o]:f,++I[o>>1],u[o>>2]+=f},p=Buffer.allocUnsafe(s+107),E=e*1e4,c=C(e);for(;;){let o=a*Atomics.add(n,0,1);if(o>=t)break;let f=Math.min(t,o+a);o>0&&(o-=107,v(r,p,0,107,o),o+=1+O(p,10,107));for(let R=0;o{n<<=3,u<<=3,I[n]=I[n]<=I[u]?I[n]:I[u],s[n]=s[n]>=s[u]?s[n]:s[u],a[n>>1]+=a[u>>1],m[n>>2]+=m[u>>2]}),tries:t}}if(ee){let e=z(import.meta.url);Z(process.argv[2],e,J())}else L.addListener("message",e=>{if(e.type===0)L.postMessage(F(e));else if(e.type===1)L.postMessage(K(e));else throw new Error("Unknown message type")}); +import{availableParallelism as J}from"node:os";import{fileURLToPath as z}from"node:url";import{isMainThread as ee,parentPort as w}from"node:worker_threads";import{closeSync as K,createWriteStream as V,fstatSync as Q,openSync as $}from"node:fs";import{stdout as j}from"node:process";function h(e,r,t){return e>r?e<=t?e:t:r}function N(e){return e=Math.ceil(e*.00390625),e+=16384-e%16384,h(e,16384,16777216)}function T(e,r){return e=Math.ceil(e/r),e+=16384-e%16384,h(e,16384,4294967296)}function P(e,r,t){for(;--t>=0;)if(e[t]===r)return t;return-1}function O(e,r,t,a){let f=1;for(;te.length&&(e=U(e,I+218)),e[0]+=218,e[f+0]=I,e[I+0]=e[1]),f=I}return[e,f]}function C(e=0,r=655360){r=Math.max(219,r);let t=new Int32Array(new SharedArrayBuffer(r<<2));return t[0]=219,t[1]=e,t}function U(e,r=0){let t=e[0];r=Math.max(r,Math.ceil(t*1.618033988749895));let a=new Int32Array(new SharedArrayBuffer(r<<2));for(let f=0;fe[n].length&&(e[n]=U(e[n],o+2),f.push(n)),e[n][0]+=2,e[n][s+0]=o,e[n][o+0]=u,e[n][o+1]=c;else{let D=e[n][o+0];n!==D&&(o=e[n][o+1]),I.push([D,o,u,c])}}s+=1,l+=1}}I.splice(0,m)}while(I.length>0);return f}function Z(e,r,t,a,f="",I){let m=new Array(r.length+1);m[0]=[t,3,0];let i=0,n=!1;do{let[s,E,l]=m[i];if(l>=216){--i;continue}m[i][1]+=1,++m[i][2];let p=e[s][E+0];if(p===0)continue;let R=e[s][p+0];s!==R&&(p=e[s][p+1],s=R),r[i]=l+32,m[++i]=[s,p+2,0];let c=e[s][p+1];c!==0&&(n&&a.write(f),n=!0,I(a,r,i,c))}while(i>=0)}import{Worker as F}from"node:worker_threads";function B(e){let r=new F(e);return r.on("error",t=>{throw t}),r.on("messageerror",t=>{throw t}),r.on("exit",t=>{if(t>1||t<0)throw new Error(`Worker ${r.threadId} exited with code ${t}`)}),r}function b(e,r){return new Promise(t=>{e.once("message",t),e.postMessage(r)})}async function H(e,r,t,a=""){t=h(t,1,256);let f=$(e,"r"),m=Q(f).size,i=T(m,t),n=N(i),s=new SharedArrayBuffer(1e4*t+1<<4),E=new Uint32Array(s,0,1),l=new Int16Array(s),p=new Int16Array(s,2),R=new Uint32Array(s,4),c=new Float64Array(s,8),u=new Array(t),o=[],D=new Array(t);for(let _=0;_{let X=A.id;for(u[X]=A.trie;o.length>0;){let d=await b(M,{type:1,a:X,b:o.pop(),counts:R,maxes:p,mins:l,sums:c,tries:u});for(let L of d.ids)u[L]=d.tries[L]}return o.push(X),M.terminate()})}await Promise.all(D),K(f);let S=V(a,{fd:a.length<1?j.fd:void 0,flags:"a",highWaterMark:1048576}),g=Buffer.allocUnsafe(100);S.write("{"),Z(u,g,o[0],S,", ",y),S.end(`} +`);function y(_,M,A,X){let d=Math.round(c[X<<1]/R[X<<2]);_.write(M.toString("utf8",0,A)),_.write("="),_.write((l[X<<3]/10).toFixed(1)),_.write("/"),_.write((d/10).toFixed(1)),_.write("/"),_.write((p[X<<3]/10).toFixed(1))}}import{readSync as x}from"fs";var k=11*48,W=111*48;function v(e,r,t){return e[r]===45?(++r,r+4>t?k-10*e[r]-e[r+2]:W-100*e[r]-10*e[r+1]-e[r+3]):r+4>t?10*e[r]+e[r+2]-k:100*e[r]+10*e[r+1]+e[r+3]-W}function G({id:e,fd:r,fileSize:t,pageSize:a,chunkSize:f,counts:I,maxes:m,mins:i,page:n,sums:s}){let E=(u,o)=>{i[u<<3]=o,m[u<<3]=o,I[u<<2]=1,s[u<<1]=o},l=(u,o)=>{u<<=3,i[u]=i[u]<=o?i[u]:o,m[u]=m[u]>=o?m[u]:o,++I[u>>1],s[u>>2]+=o},p=Buffer.allocUnsafe(f+107),R=e*1e4,c=C(e);for(;;){let u=a*Atomics.add(n,0,1);if(u>=t)break;let o=u>0?16384:0;x(r,p,0,o,u-o);let D=1+P(p,10,o);for(let S=Math.min(t,u+a);u{n<<=3,s<<=3,I[n]=I[n]<=I[s]?I[n]:I[s],f[n]=f[n]>=f[s]?f[n]:f[s],a[n>>1]+=a[s>>1],m[n>>2]+=m[s>>2]}),tries:t}}if(ee){let e=z(import.meta.url);H(process.argv[2],e,J())}else w.addListener("message",e=>{if(e.type===0)w.postMessage(G(e));else if(e.type===1)w.postMessage(Y(e));else throw new Error("Unknown message type")}); //# sourceMappingURL=index.mjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index 05973a0..457c53b 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../src/index.ts", "../src/main.ts", "../src/utils/stream.ts", "../src/utils/utf8Trie.ts", "../src/utils/worker.ts", "../src/worker.ts", "../src/utils/parse.ts"], - "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport { RequestType, type Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", (msg: Request) => {\n if (msg.type === RequestType.PROCESS) {\n parentPort!.postMessage(runWorker(msg as ProcessRequest));\n } else if (msg.type === RequestType.MERGE) {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { closeSync, createWriteStream, fstatSync, openSync, WriteStream } from \"node:fs\";\nimport { stdout } from \"node:process\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { RequestType } from \"./types/request\";\nimport { clamp, getChunkSize, getPageSize } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Open the given file\n const fd = openSync(filePath, \"r\");\n\n // Get file stats\n const fstats = fstatSync(fd);\n const fileSize = fstats.size;\n const pageSize = getPageSize(fileSize, maxWorkers);\n const chunkSize = getChunkSize(pageSize);\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const page = new Uint32Array(valBuf, 0, 1);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: RequestType.PROCESS,\n id: i,\n // I/O\n fd,\n fileSize,\n pageSize,\n chunkSize,\n // Shared memory\n counts,\n maxes,\n mins,\n page,\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[a] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: RequestType.MERGE,\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Close the file\n closeSync(fd);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? stdout.fd : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { Config } from \"../constants/config\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Calculates a chunk size based on a given page size.\n *\n * @param size - The page size.\n *\n * @returns The calculated chunk size.\n */\nexport function getChunkSize(size: number): number {\n // Get size percentage\n size *= Config.CHUNK_SIZE_RATIO;\n // Get nearest power\n size = Math.round(Math.log2(size));\n // Calculate high water mark\n size = 2 ** size;\n // Clamp value\n return clamp(size, Config.CHUNK_SIZE_MIN, Config.CHUNK_SIZE_MAX);\n}\n\n/**\n * Calculates a page size based on a given file size.\n *\n * @param fileSize - The file size.\n * @param workers - The number of workers the file will be split across.\n *\n * @returns The calculated page size.\n */\nexport function getPageSize(fileSize: number, workers: number): number {\n return Math.max(Config.CHUNK_SIZE_MIN, Math.ceil(fileSize / workers));\n}\n\n/**\n * Returns the index of the last occurrence of a \n * specified value in an array, or `-1` if it's not present.\n * \n * @param array - The array to search through.\n * @param searchElement \u2014 The value to locate in the array.\n * @param max \u2014 The array index at which to begin searching backward.\n * \n * @returns the index of the last occurrence, or `-1` if it's not present.\n */\nexport function lastIndexOf(array: ArrayLike, searchElement: T, max: number): number {\n while (--max >= 0) {\n if (array[max] === searchElement) {\n return max;\n }\n }\n return -1;\n}", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown: number[] = [];\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.push(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return grown;\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"node:worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { readSync } from \"fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { lastIndexOf } from \"./utils/stream\";\n\nexport function run({\n id,\n // I/O\n fd,\n fileSize,\n pageSize,\n chunkSize,\n // Shared memory\n counts,\n maxes,\n mins,\n page,\n sums,\n}: ProcessRequest): ProcessResponse {\n const newStation = (index: number, temp: number): void => {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n };\n\n const updateStation = (index: number, temp: number): void => {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n };\n\n // Initialize constants\n const chunk = Buffer.allocUnsafe(chunkSize + BRC.MAX_ENTRY_LEN);\n let stations = id * BRC.MAX_STATIONS;\n let trie = createTrie(id);\n\n // For each page\n while (true) {\n\n // Get page start\n let start = pageSize * Atomics.add(page, 0, 1);\n if (start >= fileSize) {\n break;\n }\n\n // Get page end\n const end = Math.min(fileSize, start + pageSize);\n\n // Align start with entry\n if (start > 0) {\n start -= BRC.MAX_ENTRY_LEN;\n readSync(fd, chunk, 0, BRC.MAX_ENTRY_LEN, start);\n start += 1 + lastIndexOf(chunk, CharCode.NEWLINE, BRC.MAX_ENTRY_LEN);\n }\n\n // For each chunk\n for (let bufI = 0; start < end; start += chunkSize) {\n // Read the chunk into memory\n let maxI = Math.min(chunkSize, end - start);\n maxI = bufI + readSync(fd, chunk, bufI, maxI, start);\n\n // For each byte\n let minI = 0;\n for (let leaf: number; bufI < maxI; ++bufI) {\n \n // If not newline\n if (chunk[bufI] !== CharCode.NEWLINE) {\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 5;\n if (chunk[semI] !== CharCode.SEMICOLON) {\n semI += 1 | (1 + ~(chunk[semI - 1] === CharCode.SEMICOLON));\n }\n\n // Add the station's name to the trie and get leaf\n [trie, leaf] = add(trie, chunk, minI, semI);\n\n // Update next entry's min\n minI = bufI + 1;\n\n // Get temperature\n const temp = parseDouble(chunk, semI + 1, bufI);\n\n // If the station existed\n leaf += TrieNodeProto.VALUE_IDX;\n if (trie[leaf] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf], temp);\n } else {\n // Add the new station's value\n trie[leaf] = ++stations;\n newStation(stations, temp);\n }\n }\n\n // Prepend any incomplete entry to the next chunk\n chunk.copyWithin(0, minI, bufI);\n\n // Update indices for the next chunk\n bufI -= minI;\n }\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n const ids = mergeLeft(tries, a, b, (ai: number, bi: number): void => {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = mins[ai] <= mins[bi] ? mins[ai] : mins[bi];\n maxes[ai] = maxes[ai] >= maxes[bi] ? maxes[ai] : maxes[bi];\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n });\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], - "mappings": "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", - "names": ["availableParallelism", "fileURLToPath", "isMainThread", "parentPort", "closeSync", "createWriteStream", "fstatSync", "openSync", "stdout", "clamp", "value", "min", "max", "getChunkSize", "size", "getPageSize", "fileSize", "workers", "lastIndexOf", "array", "searchElement", "add", "trie", "key", "min", "max", "index", "child", "grow", "createTrie", "id", "size", "trie", "grow", "minSize", "length", "next", "i", "mergeLeft", "tries", "at", "bt", "mergeFn", "grown", "queue", "Q", "q", "ai", "bi", "bvi", "avi", "bn", "ri", "rt", "li", "lt", "print", "key", "trieIndex", "stream", "separator", "callbackFn", "stack", "top", "tail", "trieI", "childPtr", "numChild", "childI", "childTrieI", "valueIndex", "Worker", "createWorker", "workerPath", "worker", "err", "code", "exec", "req", "resolve", "run", "filePath", "workerPath", "maxWorkers", "outPath", "clamp", "fd", "openSync", "fileSize", "fstatSync", "pageSize", "getPageSize", "chunkSize", "getChunkSize", "valBuf", "page", "mins", "maxes", "counts", "sums", "tries", "unmerged", "tasks", "i", "worker", "createWorker", "exec", "res", "a", "id", "closeSync", "out", "createWriteStream", "stdout", "buffer", "print", "printStation", "stream", "name", "nameLen", "vi", "avg", "readSync", "CHAR_ZERO_11", "CHAR_ZERO_111", "parseDouble", "b", "min", "max", "run", "id", "fd", "fileSize", "pageSize", "chunkSize", "counts", "maxes", "mins", "page", "sums", "newStation", "index", "temp", "updateStation", "chunk", "stations", "trie", "createTrie", "start", "end", "readSync", "lastIndexOf", "bufI", "maxI", "minI", "leaf", "semI", "add", "parseDouble", "merge", "a", "b", "tries", "mergeLeft", "ai", "bi", "isMainThread", "workerPath", "fileURLToPath", "run", "availableParallelism", "parentPort", "msg", "merge"] + "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport { RequestType, type Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", (msg: Request) => {\n if (msg.type === RequestType.PROCESS) {\n parentPort!.postMessage(runWorker(msg as ProcessRequest));\n } else if (msg.type === RequestType.MERGE) {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { closeSync, createWriteStream, fstatSync, openSync, WriteStream } from \"node:fs\";\nimport { stdout } from \"node:process\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { RequestType } from \"./types/request\";\nimport { clamp, getChunkSize, getPageSize } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Open the given file\n const fd = openSync(filePath, \"r\");\n\n // Get file stats\n const fstats = fstatSync(fd);\n const fileSize = fstats.size;\n const pageSize = getPageSize(fileSize, maxWorkers);\n const chunkSize = getChunkSize(pageSize);\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const page = new Uint32Array(valBuf, 0, 1);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: RequestType.PROCESS,\n id: i,\n // I/O\n fd,\n fileSize,\n pageSize,\n chunkSize,\n // Shared memory\n counts,\n maxes,\n mins,\n page,\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[a] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: RequestType.MERGE,\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Close the file\n closeSync(fd);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? stdout.fd : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { Config } from \"../constants/config\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Calculates a chunk size based on a given page size.\n *\n * @param size - The page size.\n *\n * @returns The calculated chunk size.\n */\nexport function getChunkSize(size: number): number {\n // Get size percentage\n size = Math.ceil(size * Config.CHUNK_SIZE_RATIO);\n // Align\n size += Config.SYS_PAGE_SIZE - (size % Config.SYS_PAGE_SIZE);\n // Clamp value\n return clamp(size, Config.CHUNK_SIZE_MIN, Config.CHUNK_SIZE_MAX);\n}\n\n/**\n * Calculates a page size based on a given file size.\n *\n * @param fileSize - The file size.\n * @param workers - The number of workers the file will be split across.\n *\n * @returns The calculated page size.\n */\nexport function getPageSize(fileSize: number, workers: number): number {\n // Divide into workers\n fileSize = Math.ceil(fileSize / workers);\n // Align\n fileSize += Config.SYS_PAGE_SIZE - (fileSize % Config.SYS_PAGE_SIZE);\n // Clamp value\n return clamp(fileSize, Config.PAGE_SIZE_MIN, Config.PAGE_SIZE_MAX);\n}\n\n/**\n * Returns the index of the last occurrence of a \n * specified value in an array, or `-1` if it's not present.\n * \n * @param array - The array to search through.\n * @param searchElement \u2014 The value to locate in the array.\n * @param max \u2014 The array index at which to begin searching backward.\n * \n * @returns the index of the last occurrence, or `-1` if it's not present.\n */\nexport function lastIndexOf(array: ArrayLike, searchElement: T, max: number): number {\n while (--max >= 0) {\n if (array[max] === searchElement) {\n return max;\n }\n }\n return -1;\n}", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown: number[] = [];\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.push(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return grown;\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"node:worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { readSync } from \"fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { lastIndexOf } from \"./utils/stream\";\nimport { Config } from \"./constants/config\";\n\nexport function run({\n id,\n // I/O\n fd,\n fileSize,\n pageSize,\n chunkSize,\n // Shared memory\n counts,\n maxes,\n mins,\n page,\n sums,\n}: ProcessRequest): ProcessResponse {\n const newStation = (index: number, temp: number): void => {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n };\n\n const updateStation = (index: number, temp: number): void => {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n };\n\n // Initialize constants\n const chunk = Buffer.allocUnsafe(chunkSize + BRC.MAX_ENTRY_LEN);\n let stations = id * BRC.MAX_STATIONS;\n let trie = createTrie(id);\n\n // For each page\n while (true) {\n\n // Get page start\n let start = pageSize * Atomics.add(page, 0, 1);\n if (start >= fileSize) {\n break;\n }\n\n // Align start with entry\n let bufI = (start > 0) ? Config.SYS_PAGE_SIZE : 0;\n readSync(fd, chunk, 0, bufI, start - bufI);\n let minI = 1 + lastIndexOf(chunk, CharCode.NEWLINE, bufI);\n\n // For each chunk\n for (const end = Math.min(fileSize, start + pageSize); start < end; start += chunkSize) {\n\n // Move incomplete entry to start of buffer\n chunk.copyWithin(0, minI, bufI);\n bufI -= minI;\n minI = 0;\n \n // Read the chunk into memory\n let maxI = Math.min(chunkSize, end - start);\n maxI = bufI + readSync(fd, chunk, bufI, maxI, start);\n\n // For each byte\n for (; bufI < maxI; ++bufI) {\n \n // If not newline\n if (chunk[bufI] !== CharCode.NEWLINE) {\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 5;\n if (chunk[semI] !== CharCode.SEMICOLON) {\n semI += 1 | (1 + ~(chunk[semI - 1] === CharCode.SEMICOLON));\n }\n\n // Add the station's name to the trie and get leaf\n let leaf: number;\n [trie, leaf] = add(trie, chunk, minI, semI);\n\n // Update next entry's min\n minI = bufI + 1;\n\n // Get temperature\n const temp = parseDouble(chunk, semI + 1, bufI);\n\n // If the station existed\n leaf += TrieNodeProto.VALUE_IDX;\n if (trie[leaf] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf], temp);\n } else {\n // Add the new station's value\n trie[leaf] = ++stations;\n newStation(stations, temp);\n }\n }\n }\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n const ids = mergeLeft(tries, a, b, (ai: number, bi: number): void => {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = mins[ai] <= mins[bi] ? mins[ai] : mins[bi];\n maxes[ai] = maxes[ai] >= maxes[bi] ? maxes[ai] : maxes[bi];\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n });\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], + "mappings": "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", + "names": ["availableParallelism", "fileURLToPath", "isMainThread", "parentPort", "closeSync", "createWriteStream", "fstatSync", "openSync", "stdout", "clamp", "value", "min", "max", "getChunkSize", "size", "getPageSize", "fileSize", "workers", "lastIndexOf", "array", "searchElement", "add", "trie", "key", "min", "max", "index", "child", "grow", "createTrie", "id", "size", "trie", "grow", "minSize", "length", "next", "i", "mergeLeft", "tries", "at", "bt", "mergeFn", "grown", "queue", "Q", "q", "ai", "bi", "bvi", "avi", "bn", "ri", "rt", "li", "lt", "print", "key", "trieIndex", "stream", "separator", "callbackFn", "stack", "top", "tail", "trieI", "childPtr", "numChild", "childI", "childTrieI", "valueIndex", "Worker", "createWorker", "workerPath", "worker", "err", "code", "exec", "req", "resolve", "run", "filePath", "workerPath", "maxWorkers", "outPath", "clamp", "fd", "openSync", "fileSize", "fstatSync", "pageSize", "getPageSize", "chunkSize", "getChunkSize", "valBuf", "page", "mins", "maxes", "counts", "sums", "tries", "unmerged", "tasks", "i", "worker", "createWorker", "exec", "res", "a", "id", "closeSync", "out", "createWriteStream", "stdout", "buffer", "print", "printStation", "stream", "name", "nameLen", "vi", "avg", "readSync", "CHAR_ZERO_11", "CHAR_ZERO_111", "parseDouble", "b", "min", "max", "run", "id", "fd", "fileSize", "pageSize", "chunkSize", "counts", "maxes", "mins", "page", "sums", "newStation", "index", "temp", "updateStation", "chunk", "stations", "trie", "createTrie", "start", "bufI", "readSync", "minI", "lastIndexOf", "end", "maxI", "semI", "leaf", "add", "parseDouble", "merge", "a", "b", "tries", "mergeLeft", "ai", "bi", "isMainThread", "workerPath", "fileURLToPath", "run", "availableParallelism", "parentPort", "msg", "merge"] } diff --git a/src/main/nodejs/havelessbemore/esbuild.config.js b/src/main/nodejs/havelessbemore/esbuild.config.js index 741fdc5..c8d4707 100644 --- a/src/main/nodejs/havelessbemore/esbuild.config.js +++ b/src/main/nodejs/havelessbemore/esbuild.config.js @@ -6,7 +6,6 @@ import pkg from "./package.json" with { type: "json" }; const options = { entryPoints: ["src/index.ts"], bundle: true, - drop: ["console"], minify: true, platform: "node", sourcemap: true, diff --git a/src/main/nodejs/havelessbemore/src/constants/config.ts b/src/main/nodejs/havelessbemore/src/constants/config.ts index a50aa50..ee0a277 100644 --- a/src/main/nodejs/havelessbemore/src/constants/config.ts +++ b/src/main/nodejs/havelessbemore/src/constants/config.ts @@ -1,26 +1,49 @@ /* eslint-disable @typescript-eslint/no-duplicate-enum-values */ export const enum Config { + /** + * The system's page size (`getconf PAGE_SIZE`). + */ + SYS_PAGE_SIZE = 16384, // 16 KiB, + /** * The minimum value in bytes for a chunk size. + * + * Should ideally be a multiple of {@link SYS_PAGE_SIZE} */ - CHUNK_SIZE_MIN = 16384, // 16 KiB + CHUNK_SIZE_MIN = SYS_PAGE_SIZE, /** * The maximum value in bytes for a chunk size. + * + * Should ideally be a multiple of {@link SYS_PAGE_SIZE} */ - CHUNK_SIZE_MAX = 8388608, // 8 MiB + CHUNK_SIZE_MAX = 16777216, // 16 MiB /** * The ratio of the page size for calculating chunk size. */ - CHUNK_SIZE_RATIO = 0.00625, + CHUNK_SIZE_RATIO = 0.00390625, /** * The `highWaterMark` for write streams. */ HIGH_WATER_MARK_OUT = 1048576, // 1 MiB + /** + * The minimum value in bytes for a page size. + * + * Should ideally be a multiple of {@link SYS_PAGE_SIZE} + */ + PAGE_SIZE_MIN = SYS_PAGE_SIZE, + + /** + * The maximum value in bytes for a page size. + * + * Should ideally be a multiple of {@link SYS_PAGE_SIZE} + */ + PAGE_SIZE_MAX = 4294967296, // 4 GiB + /** * The minimum number of web workers (inclusive). */ @@ -47,5 +70,5 @@ export const enum Config { * thus 1M trie nodes of ~0.85 KB each. This should be * considered when increasing the number of workers. */ - WORKERS_MAX = 512, + WORKERS_MAX = 256, } diff --git a/src/main/nodejs/havelessbemore/src/utils/stream.ts b/src/main/nodejs/havelessbemore/src/utils/stream.ts index b44e9c7..31fa3d2 100644 --- a/src/main/nodejs/havelessbemore/src/utils/stream.ts +++ b/src/main/nodejs/havelessbemore/src/utils/stream.ts @@ -22,11 +22,9 @@ export function clamp(value: number, min: number, max: number): number { */ export function getChunkSize(size: number): number { // Get size percentage - size *= Config.CHUNK_SIZE_RATIO; - // Get nearest power - size = Math.round(Math.log2(size)); - // Calculate high water mark - size = 2 ** size; + size = Math.ceil(size * Config.CHUNK_SIZE_RATIO); + // Align + size += Config.SYS_PAGE_SIZE - (size % Config.SYS_PAGE_SIZE); // Clamp value return clamp(size, Config.CHUNK_SIZE_MIN, Config.CHUNK_SIZE_MAX); } @@ -40,7 +38,12 @@ export function getChunkSize(size: number): number { * @returns The calculated page size. */ export function getPageSize(fileSize: number, workers: number): number { - return Math.max(Config.CHUNK_SIZE_MIN, Math.ceil(fileSize / workers)); + // Divide into workers + fileSize = Math.ceil(fileSize / workers); + // Align + fileSize += Config.SYS_PAGE_SIZE - (fileSize % Config.SYS_PAGE_SIZE); + // Clamp value + return clamp(fileSize, Config.PAGE_SIZE_MIN, Config.PAGE_SIZE_MAX); } /** diff --git a/src/main/nodejs/havelessbemore/src/worker.ts b/src/main/nodejs/havelessbemore/src/worker.ts index db83929..eb136ca 100644 --- a/src/main/nodejs/havelessbemore/src/worker.ts +++ b/src/main/nodejs/havelessbemore/src/worker.ts @@ -10,6 +10,7 @@ import { CharCode, Trie, TrieNodeProto } from "./constants/utf8"; import { parseDouble } from "./utils/parse"; import { add, createTrie, mergeLeft } from "./utils/utf8Trie"; import { lastIndexOf } from "./utils/stream"; +import { Config } from "./constants/config"; export function run({ id, @@ -54,25 +55,25 @@ export function run({ break; } - // Get page end - const end = Math.min(fileSize, start + pageSize); - // Align start with entry - if (start > 0) { - start -= BRC.MAX_ENTRY_LEN; - readSync(fd, chunk, 0, BRC.MAX_ENTRY_LEN, start); - start += 1 + lastIndexOf(chunk, CharCode.NEWLINE, BRC.MAX_ENTRY_LEN); - } + let bufI = (start > 0) ? Config.SYS_PAGE_SIZE : 0; + readSync(fd, chunk, 0, bufI, start - bufI); + let minI = 1 + lastIndexOf(chunk, CharCode.NEWLINE, bufI); // For each chunk - for (let bufI = 0; start < end; start += chunkSize) { + for (const end = Math.min(fileSize, start + pageSize); start < end; start += chunkSize) { + + // Move incomplete entry to start of buffer + chunk.copyWithin(0, minI, bufI); + bufI -= minI; + minI = 0; + // Read the chunk into memory let maxI = Math.min(chunkSize, end - start); maxI = bufI + readSync(fd, chunk, bufI, maxI, start); // For each byte - let minI = 0; - for (let leaf: number; bufI < maxI; ++bufI) { + for (; bufI < maxI; ++bufI) { // If not newline if (chunk[bufI] !== CharCode.NEWLINE) { @@ -86,6 +87,7 @@ export function run({ } // Add the station's name to the trie and get leaf + let leaf: number; [trie, leaf] = add(trie, chunk, minI, semI); // Update next entry's min @@ -105,12 +107,6 @@ export function run({ newStation(stations, temp); } } - - // Prepend any incomplete entry to the next chunk - chunk.copyWithin(0, minI, bufI); - - // Update indices for the next chunk - bufI -= minI; } } From a9e603c9b228d86bdce2f1d9707bb3033cfe890c Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Thu, 30 May 2024 22:10:34 -0400 Subject: [PATCH 66/69] Refactor worker hot loop --- src/main/nodejs/havelessbemore/dist/index.mjs | 4 ++-- src/main/nodejs/havelessbemore/dist/index.mjs.map | 4 ++-- src/main/nodejs/havelessbemore/src/worker.ts | 15 ++++++++------- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index 45948fd..5cac8a9 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -1,3 +1,3 @@ -import{availableParallelism as J}from"node:os";import{fileURLToPath as z}from"node:url";import{isMainThread as ee,parentPort as w}from"node:worker_threads";import{closeSync as K,createWriteStream as V,fstatSync as Q,openSync as $}from"node:fs";import{stdout as j}from"node:process";function h(e,r,t){return e>r?e<=t?e:t:r}function N(e){return e=Math.ceil(e*.00390625),e+=16384-e%16384,h(e,16384,16777216)}function T(e,r){return e=Math.ceil(e/r),e+=16384-e%16384,h(e,16384,4294967296)}function P(e,r,t){for(;--t>=0;)if(e[t]===r)return t;return-1}function O(e,r,t,a){let f=1;for(;te.length&&(e=U(e,I+218)),e[0]+=218,e[f+0]=I,e[I+0]=e[1]),f=I}return[e,f]}function C(e=0,r=655360){r=Math.max(219,r);let t=new Int32Array(new SharedArrayBuffer(r<<2));return t[0]=219,t[1]=e,t}function U(e,r=0){let t=e[0];r=Math.max(r,Math.ceil(t*1.618033988749895));let a=new Int32Array(new SharedArrayBuffer(r<<2));for(let f=0;fe[n].length&&(e[n]=U(e[n],o+2),f.push(n)),e[n][0]+=2,e[n][s+0]=o,e[n][o+0]=u,e[n][o+1]=c;else{let D=e[n][o+0];n!==D&&(o=e[n][o+1]),I.push([D,o,u,c])}}s+=1,l+=1}}I.splice(0,m)}while(I.length>0);return f}function Z(e,r,t,a,f="",I){let m=new Array(r.length+1);m[0]=[t,3,0];let i=0,n=!1;do{let[s,E,l]=m[i];if(l>=216){--i;continue}m[i][1]+=1,++m[i][2];let p=e[s][E+0];if(p===0)continue;let R=e[s][p+0];s!==R&&(p=e[s][p+1],s=R),r[i]=l+32,m[++i]=[s,p+2,0];let c=e[s][p+1];c!==0&&(n&&a.write(f),n=!0,I(a,r,i,c))}while(i>=0)}import{Worker as F}from"node:worker_threads";function B(e){let r=new F(e);return r.on("error",t=>{throw t}),r.on("messageerror",t=>{throw t}),r.on("exit",t=>{if(t>1||t<0)throw new Error(`Worker ${r.threadId} exited with code ${t}`)}),r}function b(e,r){return new Promise(t=>{e.once("message",t),e.postMessage(r)})}async function H(e,r,t,a=""){t=h(t,1,256);let f=$(e,"r"),m=Q(f).size,i=T(m,t),n=N(i),s=new SharedArrayBuffer(1e4*t+1<<4),E=new Uint32Array(s,0,1),l=new Int16Array(s),p=new Int16Array(s,2),R=new Uint32Array(s,4),c=new Float64Array(s,8),u=new Array(t),o=[],D=new Array(t);for(let _=0;_{let X=A.id;for(u[X]=A.trie;o.length>0;){let d=await b(M,{type:1,a:X,b:o.pop(),counts:R,maxes:p,mins:l,sums:c,tries:u});for(let L of d.ids)u[L]=d.tries[L]}return o.push(X),M.terminate()})}await Promise.all(D),K(f);let S=V(a,{fd:a.length<1?j.fd:void 0,flags:"a",highWaterMark:1048576}),g=Buffer.allocUnsafe(100);S.write("{"),Z(u,g,o[0],S,", ",y),S.end(`} -`);function y(_,M,A,X){let d=Math.round(c[X<<1]/R[X<<2]);_.write(M.toString("utf8",0,A)),_.write("="),_.write((l[X<<3]/10).toFixed(1)),_.write("/"),_.write((d/10).toFixed(1)),_.write("/"),_.write((p[X<<3]/10).toFixed(1))}}import{readSync as x}from"fs";var k=11*48,W=111*48;function v(e,r,t){return e[r]===45?(++r,r+4>t?k-10*e[r]-e[r+2]:W-100*e[r]-10*e[r+1]-e[r+3]):r+4>t?10*e[r]+e[r+2]-k:100*e[r]+10*e[r+1]+e[r+3]-W}function G({id:e,fd:r,fileSize:t,pageSize:a,chunkSize:f,counts:I,maxes:m,mins:i,page:n,sums:s}){let E=(u,o)=>{i[u<<3]=o,m[u<<3]=o,I[u<<2]=1,s[u<<1]=o},l=(u,o)=>{u<<=3,i[u]=i[u]<=o?i[u]:o,m[u]=m[u]>=o?m[u]:o,++I[u>>1],s[u>>2]+=o},p=Buffer.allocUnsafe(f+107),R=e*1e4,c=C(e);for(;;){let u=a*Atomics.add(n,0,1);if(u>=t)break;let o=u>0?16384:0;x(r,p,0,o,u-o);let D=1+P(p,10,o);for(let S=Math.min(t,u+a);u{n<<=3,s<<=3,I[n]=I[n]<=I[s]?I[n]:I[s],f[n]=f[n]>=f[s]?f[n]:f[s],a[n>>1]+=a[s>>1],m[n>>2]+=m[s>>2]}),tries:t}}if(ee){let e=z(import.meta.url);H(process.argv[2],e,J())}else w.addListener("message",e=>{if(e.type===0)w.postMessage(G(e));else if(e.type===1)w.postMessage(Y(e));else throw new Error("Unknown message type")}); +import{availableParallelism as J}from"node:os";import{fileURLToPath as z}from"node:url";import{isMainThread as ee,parentPort as w}from"node:worker_threads";import{closeSync as K,createWriteStream as V,fstatSync as Q,openSync as $}from"node:fs";import{stdout as j}from"node:process";function h(e,r,t){return e>r?e<=t?e:t:r}function N(e){return e=Math.ceil(e*.00390625),e+=16384-e%16384,h(e,16384,16777216)}function P(e,r){return e=Math.ceil(e/r),e+=16384-e%16384,h(e,16384,4294967296)}function T(e,r,t){for(;--t>=0;)if(e[t]===r)return t;return-1}function O(e,r,t,a){let f=1;for(;te.length&&(e=U(e,I+218)),e[0]+=218,e[f+0]=I,e[I+0]=e[1]),f=I}return[e,f]}function C(e=0,r=655360){r=Math.max(219,r);let t=new Int32Array(new SharedArrayBuffer(r<<2));return t[0]=219,t[1]=e,t}function U(e,r=0){let t=e[0];r=Math.max(r,Math.ceil(t*1.618033988749895));let a=new Int32Array(new SharedArrayBuffer(r<<2));for(let f=0;fe[n].length&&(e[n]=U(e[n],o+2),f.push(n)),e[n][0]+=2,e[n][s+0]=o,e[n][o+0]=u,e[n][o+1]=c;else{let D=e[n][o+0];n!==D&&(o=e[n][o+1]),I.push([D,o,u,c])}}s+=1,E+=1}}I.splice(0,m)}while(I.length>0);return f}function Z(e,r,t,a,f="",I){let m=new Array(r.length+1);m[0]=[t,3,0];let i=0,n=!1;do{let[s,l,E]=m[i];if(E>=216){--i;continue}m[i][1]+=1,++m[i][2];let p=e[s][l+0];if(p===0)continue;let R=e[s][p+0];s!==R&&(p=e[s][p+1],s=R),r[i]=E+32,m[++i]=[s,p+2,0];let c=e[s][p+1];c!==0&&(n&&a.write(f),n=!0,I(a,r,i,c))}while(i>=0)}import{Worker as F}from"node:worker_threads";function B(e){let r=new F(e);return r.on("error",t=>{throw t}),r.on("messageerror",t=>{throw t}),r.on("exit",t=>{if(t>1||t<0)throw new Error(`Worker ${r.threadId} exited with code ${t}`)}),r}function b(e,r){return new Promise(t=>{e.once("message",t),e.postMessage(r)})}async function H(e,r,t,a=""){t=h(t,1,256);let f=$(e,"r"),m=Q(f).size,i=P(m,t),n=N(i),s=new SharedArrayBuffer(1e4*t+1<<4),l=new Uint32Array(s,0,1),E=new Int16Array(s),p=new Int16Array(s,2),R=new Uint32Array(s,4),c=new Float64Array(s,8),u=new Array(t),o=[],D=new Array(t);for(let _=0;_{let y=g.id;for(u[y]=g.trie;o.length>0;){let d=await b(S,{type:1,a:y,b:o.pop(),counts:R,maxes:p,mins:E,sums:c,tries:u});for(let L of d.ids)u[L]=d.tries[L]}return o.push(y),S.terminate()})}await Promise.all(D),K(f);let A=V(a,{fd:a.length<1?j.fd:void 0,flags:"a",highWaterMark:1048576}),M=Buffer.allocUnsafe(100);A.write("{"),Z(u,M,o[0],A,", ",X),A.end(`} +`);function X(_,S,g,y){let d=Math.round(c[y<<1]/R[y<<2]);_.write(S.toString("utf8",0,g)),_.write("="),_.write((E[y<<3]/10).toFixed(1)),_.write("/"),_.write((d/10).toFixed(1)),_.write("/"),_.write((p[y<<3]/10).toFixed(1))}}import{readSync as v}from"fs";var k=11*48,W=111*48;function G(e,r,t){return e[r]===45?(++r,r+4>t?k-10*e[r]-e[r+2]:W-100*e[r]-10*e[r+1]-e[r+3]):r+4>t?10*e[r]+e[r+2]-k:100*e[r]+10*e[r+1]+e[r+3]-W}function x({id:e,fd:r,fileSize:t,pageSize:a,chunkSize:f,counts:I,maxes:m,mins:i,page:n,sums:s}){let l=(u,o)=>{i[u<<3]=o,m[u<<3]=o,I[u<<2]=1,s[u<<1]=o},E=(u,o)=>{u<<=3,i[u]=i[u]<=o?i[u]:o,m[u]=m[u]>=o?m[u]:o,++I[u>>1],s[u>>2]+=o},p=Buffer.allocUnsafe(f+16384),R=e*1e4,c=C(e);for(;;){let u=a*Atomics.add(n,0,1);if(u>=t)break;let o=u>0?16384:0;v(r,p,0,o,u-o);let D=1+T(p,10,o);for(let A=Math.min(t,u+a);u{n<<=3,s<<=3,I[n]=I[n]<=I[s]?I[n]:I[s],f[n]=f[n]>=f[s]?f[n]:f[s],a[n>>1]+=a[s>>1],m[n>>2]+=m[s>>2]}),tries:t}}if(ee){let e=z(import.meta.url);H(process.argv[2],e,J())}else w.addListener("message",e=>{if(e.type===0)w.postMessage(x(e));else if(e.type===1)w.postMessage(Y(e));else throw new Error("Unknown message type")}); //# sourceMappingURL=index.mjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index 457c53b..5ef983d 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../src/index.ts", "../src/main.ts", "../src/utils/stream.ts", "../src/utils/utf8Trie.ts", "../src/utils/worker.ts", "../src/worker.ts", "../src/utils/parse.ts"], - "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport { RequestType, type Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", (msg: Request) => {\n if (msg.type === RequestType.PROCESS) {\n parentPort!.postMessage(runWorker(msg as ProcessRequest));\n } else if (msg.type === RequestType.MERGE) {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { closeSync, createWriteStream, fstatSync, openSync, WriteStream } from \"node:fs\";\nimport { stdout } from \"node:process\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { RequestType } from \"./types/request\";\nimport { clamp, getChunkSize, getPageSize } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Open the given file\n const fd = openSync(filePath, \"r\");\n\n // Get file stats\n const fstats = fstatSync(fd);\n const fileSize = fstats.size;\n const pageSize = getPageSize(fileSize, maxWorkers);\n const chunkSize = getChunkSize(pageSize);\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const page = new Uint32Array(valBuf, 0, 1);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: RequestType.PROCESS,\n id: i,\n // I/O\n fd,\n fileSize,\n pageSize,\n chunkSize,\n // Shared memory\n counts,\n maxes,\n mins,\n page,\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[a] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: RequestType.MERGE,\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Close the file\n closeSync(fd);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? stdout.fd : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { Config } from \"../constants/config\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Calculates a chunk size based on a given page size.\n *\n * @param size - The page size.\n *\n * @returns The calculated chunk size.\n */\nexport function getChunkSize(size: number): number {\n // Get size percentage\n size = Math.ceil(size * Config.CHUNK_SIZE_RATIO);\n // Align\n size += Config.SYS_PAGE_SIZE - (size % Config.SYS_PAGE_SIZE);\n // Clamp value\n return clamp(size, Config.CHUNK_SIZE_MIN, Config.CHUNK_SIZE_MAX);\n}\n\n/**\n * Calculates a page size based on a given file size.\n *\n * @param fileSize - The file size.\n * @param workers - The number of workers the file will be split across.\n *\n * @returns The calculated page size.\n */\nexport function getPageSize(fileSize: number, workers: number): number {\n // Divide into workers\n fileSize = Math.ceil(fileSize / workers);\n // Align\n fileSize += Config.SYS_PAGE_SIZE - (fileSize % Config.SYS_PAGE_SIZE);\n // Clamp value\n return clamp(fileSize, Config.PAGE_SIZE_MIN, Config.PAGE_SIZE_MAX);\n}\n\n/**\n * Returns the index of the last occurrence of a \n * specified value in an array, or `-1` if it's not present.\n * \n * @param array - The array to search through.\n * @param searchElement \u2014 The value to locate in the array.\n * @param max \u2014 The array index at which to begin searching backward.\n * \n * @returns the index of the last occurrence, or `-1` if it's not present.\n */\nexport function lastIndexOf(array: ArrayLike, searchElement: T, max: number): number {\n while (--max >= 0) {\n if (array[max] === searchElement) {\n return max;\n }\n }\n return -1;\n}", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown: number[] = [];\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.push(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return grown;\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"node:worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { readSync } from \"fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { lastIndexOf } from \"./utils/stream\";\nimport { Config } from \"./constants/config\";\n\nexport function run({\n id,\n // I/O\n fd,\n fileSize,\n pageSize,\n chunkSize,\n // Shared memory\n counts,\n maxes,\n mins,\n page,\n sums,\n}: ProcessRequest): ProcessResponse {\n const newStation = (index: number, temp: number): void => {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n };\n\n const updateStation = (index: number, temp: number): void => {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n };\n\n // Initialize constants\n const chunk = Buffer.allocUnsafe(chunkSize + BRC.MAX_ENTRY_LEN);\n let stations = id * BRC.MAX_STATIONS;\n let trie = createTrie(id);\n\n // For each page\n while (true) {\n\n // Get page start\n let start = pageSize * Atomics.add(page, 0, 1);\n if (start >= fileSize) {\n break;\n }\n\n // Align start with entry\n let bufI = (start > 0) ? Config.SYS_PAGE_SIZE : 0;\n readSync(fd, chunk, 0, bufI, start - bufI);\n let minI = 1 + lastIndexOf(chunk, CharCode.NEWLINE, bufI);\n\n // For each chunk\n for (const end = Math.min(fileSize, start + pageSize); start < end; start += chunkSize) {\n\n // Move incomplete entry to start of buffer\n chunk.copyWithin(0, minI, bufI);\n bufI -= minI;\n minI = 0;\n \n // Read the chunk into memory\n let maxI = Math.min(chunkSize, end - start);\n maxI = bufI + readSync(fd, chunk, bufI, maxI, start);\n\n // For each byte\n for (; bufI < maxI; ++bufI) {\n \n // If not newline\n if (chunk[bufI] !== CharCode.NEWLINE) {\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 5;\n if (chunk[semI] !== CharCode.SEMICOLON) {\n semI += 1 | (1 + ~(chunk[semI - 1] === CharCode.SEMICOLON));\n }\n\n // Add the station's name to the trie and get leaf\n let leaf: number;\n [trie, leaf] = add(trie, chunk, minI, semI);\n\n // Update next entry's min\n minI = bufI + 1;\n\n // Get temperature\n const temp = parseDouble(chunk, semI + 1, bufI);\n\n // If the station existed\n leaf += TrieNodeProto.VALUE_IDX;\n if (trie[leaf] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf], temp);\n } else {\n // Add the new station's value\n trie[leaf] = ++stations;\n newStation(stations, temp);\n }\n }\n }\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n const ids = mergeLeft(tries, a, b, (ai: number, bi: number): void => {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = mins[ai] <= mins[bi] ? mins[ai] : mins[bi];\n maxes[ai] = maxes[ai] >= maxes[bi] ? maxes[ai] : maxes[bi];\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n });\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], - "mappings": "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", + "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport { RequestType, type Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", (msg: Request) => {\n if (msg.type === RequestType.PROCESS) {\n parentPort!.postMessage(runWorker(msg as ProcessRequest));\n } else if (msg.type === RequestType.MERGE) {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { closeSync, createWriteStream, fstatSync, openSync, WriteStream } from \"node:fs\";\nimport { stdout } from \"node:process\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { RequestType } from \"./types/request\";\nimport { clamp, getChunkSize, getPageSize } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Open the given file\n const fd = openSync(filePath, \"r\");\n\n // Get file stats\n const fstats = fstatSync(fd);\n const fileSize = fstats.size;\n const pageSize = getPageSize(fileSize, maxWorkers);\n const chunkSize = getChunkSize(pageSize);\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const page = new Uint32Array(valBuf, 0, 1);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: RequestType.PROCESS,\n id: i,\n // I/O\n fd,\n fileSize,\n pageSize,\n chunkSize,\n // Shared memory\n counts,\n maxes,\n mins,\n page,\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[a] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: RequestType.MERGE,\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Close the file\n closeSync(fd);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? stdout.fd : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { Config } from \"../constants/config\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Calculates a chunk size based on a given page size.\n *\n * @param size - The page size.\n *\n * @returns The calculated chunk size.\n */\nexport function getChunkSize(size: number): number {\n // Get size percentage\n size = Math.ceil(size * Config.CHUNK_SIZE_RATIO);\n // Align\n size += Config.SYS_PAGE_SIZE - (size % Config.SYS_PAGE_SIZE);\n // Clamp value\n return clamp(size, Config.CHUNK_SIZE_MIN, Config.CHUNK_SIZE_MAX);\n}\n\n/**\n * Calculates a page size based on a given file size.\n *\n * @param fileSize - The file size.\n * @param workers - The number of workers the file will be split across.\n *\n * @returns The calculated page size.\n */\nexport function getPageSize(fileSize: number, workers: number): number {\n // Divide into workers\n fileSize = Math.ceil(fileSize / workers);\n // Align\n fileSize += Config.SYS_PAGE_SIZE - (fileSize % Config.SYS_PAGE_SIZE);\n // Clamp value\n return clamp(fileSize, Config.PAGE_SIZE_MIN, Config.PAGE_SIZE_MAX);\n}\n\n/**\n * Returns the index of the last occurrence of a \n * specified value in an array, or `-1` if it's not present.\n * \n * @param array - The array to search through.\n * @param searchElement \u2014 The value to locate in the array.\n * @param max \u2014 The array index at which to begin searching backward.\n * \n * @returns the index of the last occurrence, or `-1` if it's not present.\n */\nexport function lastIndexOf(array: ArrayLike, searchElement: T, max: number): number {\n while (--max >= 0) {\n if (array[max] === searchElement) {\n return max;\n }\n }\n return -1;\n}", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown: number[] = [];\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.push(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return grown;\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"node:worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { readSync } from \"fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { lastIndexOf } from \"./utils/stream\";\nimport { Config } from \"./constants/config\";\n\nexport function run({\n id,\n // I/O\n fd,\n fileSize,\n pageSize,\n chunkSize,\n // Shared memory\n counts,\n maxes,\n mins,\n page,\n sums,\n}: ProcessRequest): ProcessResponse {\n const newStation = (index: number, temp: number): void => {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n };\n\n const updateStation = (index: number, temp: number): void => {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n };\n\n // Initialize constants\n const chunk = Buffer.allocUnsafe(chunkSize + Config.SYS_PAGE_SIZE);\n let stations = id * BRC.MAX_STATIONS;\n let trie = createTrie(id);\n\n // For each page\n while (true) {\n\n // Get page start\n let start = pageSize * Atomics.add(page, 0, 1);\n if (start >= fileSize) {\n break;\n }\n\n // Align start with entry\n let bufI = (start > 0) ? Config.SYS_PAGE_SIZE : 0;\n readSync(fd, chunk, 0, bufI, start - bufI);\n let minI = 1 + lastIndexOf(chunk, CharCode.NEWLINE, bufI);\n\n // For each chunk\n for (const end = Math.min(fileSize, start + pageSize); start < end; start += chunkSize) {\n\n // Move incomplete entry to start of buffer\n let maxI = Config.SYS_PAGE_SIZE - bufI + minI;\n chunk.copyWithin(maxI, minI, bufI);\n bufI = Config.SYS_PAGE_SIZE;\n minI = maxI;\n \n // Read the chunk into memory\n maxI = Math.min(chunkSize, end - start);\n maxI = readSync(fd, chunk, bufI, maxI, start);\n\n // For each byte\n for (maxI += bufI; bufI < maxI; ++bufI) {\n \n // If not newline\n if (chunk[bufI] !== CharCode.NEWLINE) {\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 5;\n if (chunk[semI] !== CharCode.SEMICOLON) {\n semI += 1 | (1 + ~(chunk[semI - 1] === CharCode.SEMICOLON));\n }\n\n // Add the station's name to the trie and get leaf\n let leaf: number;\n [trie, leaf] = add(trie, chunk, minI, semI);\n\n // Update next entry's min\n minI = bufI + 1;\n\n // Get temperature\n const temp = parseDouble(chunk, semI + 1, bufI);\n\n // If the station existed\n leaf += TrieNodeProto.VALUE_IDX;\n if (trie[leaf] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf], temp);\n } else {\n // Add the new station's value\n trie[leaf] = ++stations;\n newStation(stations, temp);\n }\n }\n }\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n const ids = mergeLeft(tries, a, b, (ai: number, bi: number): void => {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = mins[ai] <= mins[bi] ? mins[ai] : mins[bi];\n maxes[ai] = maxes[ai] >= maxes[bi] ? maxes[ai] : maxes[bi];\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n });\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], + "mappings": "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", "names": ["availableParallelism", "fileURLToPath", "isMainThread", "parentPort", "closeSync", "createWriteStream", "fstatSync", "openSync", "stdout", "clamp", "value", "min", "max", "getChunkSize", "size", "getPageSize", "fileSize", "workers", "lastIndexOf", "array", "searchElement", "add", "trie", "key", "min", "max", "index", "child", "grow", "createTrie", "id", "size", "trie", "grow", "minSize", "length", "next", "i", "mergeLeft", "tries", "at", "bt", "mergeFn", "grown", "queue", "Q", "q", "ai", "bi", "bvi", "avi", "bn", "ri", "rt", "li", "lt", "print", "key", "trieIndex", "stream", "separator", "callbackFn", "stack", "top", "tail", "trieI", "childPtr", "numChild", "childI", "childTrieI", "valueIndex", "Worker", "createWorker", "workerPath", "worker", "err", "code", "exec", "req", "resolve", "run", "filePath", "workerPath", "maxWorkers", "outPath", "clamp", "fd", "openSync", "fileSize", "fstatSync", "pageSize", "getPageSize", "chunkSize", "getChunkSize", "valBuf", "page", "mins", "maxes", "counts", "sums", "tries", "unmerged", "tasks", "i", "worker", "createWorker", "exec", "res", "a", "id", "closeSync", "out", "createWriteStream", "stdout", "buffer", "print", "printStation", "stream", "name", "nameLen", "vi", "avg", "readSync", "CHAR_ZERO_11", "CHAR_ZERO_111", "parseDouble", "b", "min", "max", "run", "id", "fd", "fileSize", "pageSize", "chunkSize", "counts", "maxes", "mins", "page", "sums", "newStation", "index", "temp", "updateStation", "chunk", "stations", "trie", "createTrie", "start", "bufI", "readSync", "minI", "lastIndexOf", "end", "maxI", "semI", "leaf", "add", "parseDouble", "merge", "a", "b", "tries", "mergeLeft", "ai", "bi", "isMainThread", "workerPath", "fileURLToPath", "run", "availableParallelism", "parentPort", "msg", "merge"] } diff --git a/src/main/nodejs/havelessbemore/src/worker.ts b/src/main/nodejs/havelessbemore/src/worker.ts index eb136ca..b17f271 100644 --- a/src/main/nodejs/havelessbemore/src/worker.ts +++ b/src/main/nodejs/havelessbemore/src/worker.ts @@ -42,7 +42,7 @@ export function run({ }; // Initialize constants - const chunk = Buffer.allocUnsafe(chunkSize + BRC.MAX_ENTRY_LEN); + const chunk = Buffer.allocUnsafe(chunkSize + Config.SYS_PAGE_SIZE); let stations = id * BRC.MAX_STATIONS; let trie = createTrie(id); @@ -64,16 +64,17 @@ export function run({ for (const end = Math.min(fileSize, start + pageSize); start < end; start += chunkSize) { // Move incomplete entry to start of buffer - chunk.copyWithin(0, minI, bufI); - bufI -= minI; - minI = 0; + let maxI = Config.SYS_PAGE_SIZE - bufI + minI; + chunk.copyWithin(maxI, minI, bufI); + bufI = Config.SYS_PAGE_SIZE; + minI = maxI; // Read the chunk into memory - let maxI = Math.min(chunkSize, end - start); - maxI = bufI + readSync(fd, chunk, bufI, maxI, start); + maxI = Math.min(chunkSize, end - start); + maxI = readSync(fd, chunk, bufI, maxI, start); // For each byte - for (; bufI < maxI; ++bufI) { + for (maxI += bufI; bufI < maxI; ++bufI) { // If not newline if (chunk[bufI] !== CharCode.NEWLINE) { From 9acc20a46a98c7d6d4e57703804a7b9ea11ac672 Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Thu, 30 May 2024 22:57:48 -0400 Subject: [PATCH 67/69] Refactor constants --- src/main/nodejs/havelessbemore/README.md | 4 +- src/main/nodejs/havelessbemore/dist/index.mjs | 4 +- .../nodejs/havelessbemore/dist/index.mjs.map | 4 +- .../havelessbemore/src/constants/config.ts | 38 ++++++++++++++----- src/main/nodejs/havelessbemore/src/main.ts | 8 +++- .../nodejs/havelessbemore/src/utils/stream.ts | 14 ++++--- src/main/nodejs/havelessbemore/src/worker.ts | 13 +++---- 7 files changed, 57 insertions(+), 28 deletions(-) diff --git a/src/main/nodejs/havelessbemore/README.md b/src/main/nodejs/havelessbemore/README.md index 90d99ca..633acb7 100644 --- a/src/main/nodejs/havelessbemore/README.md +++ b/src/main/nodejs/havelessbemore/README.md @@ -14,7 +14,7 @@ ### Results -- Min: 11.4s +- Min: 11.1s - Avg: 11.9s - Max: 12.1s - Samples: 10 runs, 5s apart @@ -30,7 +30,7 @@ - OS: MacOS Sonoma - Other: - - NodeJS: v20.13.1 + - NodeJS: v20.14.0 - Input file: ~13.8 GB ## Build diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs index 5cac8a9..217a22e 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ b/src/main/nodejs/havelessbemore/dist/index.mjs @@ -1,3 +1,3 @@ -import{availableParallelism as J}from"node:os";import{fileURLToPath as z}from"node:url";import{isMainThread as ee,parentPort as w}from"node:worker_threads";import{closeSync as K,createWriteStream as V,fstatSync as Q,openSync as $}from"node:fs";import{stdout as j}from"node:process";function h(e,r,t){return e>r?e<=t?e:t:r}function N(e){return e=Math.ceil(e*.00390625),e+=16384-e%16384,h(e,16384,16777216)}function P(e,r){return e=Math.ceil(e/r),e+=16384-e%16384,h(e,16384,4294967296)}function T(e,r,t){for(;--t>=0;)if(e[t]===r)return t;return-1}function O(e,r,t,a){let f=1;for(;te.length&&(e=U(e,I+218)),e[0]+=218,e[f+0]=I,e[I+0]=e[1]),f=I}return[e,f]}function C(e=0,r=655360){r=Math.max(219,r);let t=new Int32Array(new SharedArrayBuffer(r<<2));return t[0]=219,t[1]=e,t}function U(e,r=0){let t=e[0];r=Math.max(r,Math.ceil(t*1.618033988749895));let a=new Int32Array(new SharedArrayBuffer(r<<2));for(let f=0;fe[n].length&&(e[n]=U(e[n],o+2),f.push(n)),e[n][0]+=2,e[n][s+0]=o,e[n][o+0]=u,e[n][o+1]=c;else{let D=e[n][o+0];n!==D&&(o=e[n][o+1]),I.push([D,o,u,c])}}s+=1,E+=1}}I.splice(0,m)}while(I.length>0);return f}function Z(e,r,t,a,f="",I){let m=new Array(r.length+1);m[0]=[t,3,0];let i=0,n=!1;do{let[s,l,E]=m[i];if(E>=216){--i;continue}m[i][1]+=1,++m[i][2];let p=e[s][l+0];if(p===0)continue;let R=e[s][p+0];s!==R&&(p=e[s][p+1],s=R),r[i]=E+32,m[++i]=[s,p+2,0];let c=e[s][p+1];c!==0&&(n&&a.write(f),n=!0,I(a,r,i,c))}while(i>=0)}import{Worker as F}from"node:worker_threads";function B(e){let r=new F(e);return r.on("error",t=>{throw t}),r.on("messageerror",t=>{throw t}),r.on("exit",t=>{if(t>1||t<0)throw new Error(`Worker ${r.threadId} exited with code ${t}`)}),r}function b(e,r){return new Promise(t=>{e.once("message",t),e.postMessage(r)})}async function H(e,r,t,a=""){t=h(t,1,256);let f=$(e,"r"),m=Q(f).size,i=P(m,t),n=N(i),s=new SharedArrayBuffer(1e4*t+1<<4),l=new Uint32Array(s,0,1),E=new Int16Array(s),p=new Int16Array(s,2),R=new Uint32Array(s,4),c=new Float64Array(s,8),u=new Array(t),o=[],D=new Array(t);for(let _=0;_{let y=g.id;for(u[y]=g.trie;o.length>0;){let d=await b(S,{type:1,a:y,b:o.pop(),counts:R,maxes:p,mins:E,sums:c,tries:u});for(let L of d.ids)u[L]=d.tries[L]}return o.push(y),S.terminate()})}await Promise.all(D),K(f);let A=V(a,{fd:a.length<1?j.fd:void 0,flags:"a",highWaterMark:1048576}),M=Buffer.allocUnsafe(100);A.write("{"),Z(u,M,o[0],A,", ",X),A.end(`} -`);function X(_,S,g,y){let d=Math.round(c[y<<1]/R[y<<2]);_.write(S.toString("utf8",0,g)),_.write("="),_.write((E[y<<3]/10).toFixed(1)),_.write("/"),_.write((d/10).toFixed(1)),_.write("/"),_.write((p[y<<3]/10).toFixed(1))}}import{readSync as v}from"fs";var k=11*48,W=111*48;function G(e,r,t){return e[r]===45?(++r,r+4>t?k-10*e[r]-e[r+2]:W-100*e[r]-10*e[r+1]-e[r+3]):r+4>t?10*e[r]+e[r+2]-k:100*e[r]+10*e[r+1]+e[r+3]-W}function x({id:e,fd:r,fileSize:t,pageSize:a,chunkSize:f,counts:I,maxes:m,mins:i,page:n,sums:s}){let l=(u,o)=>{i[u<<3]=o,m[u<<3]=o,I[u<<2]=1,s[u<<1]=o},E=(u,o)=>{u<<=3,i[u]=i[u]<=o?i[u]:o,m[u]=m[u]>=o?m[u]:o,++I[u>>1],s[u>>2]+=o},p=Buffer.allocUnsafe(f+16384),R=e*1e4,c=C(e);for(;;){let u=a*Atomics.add(n,0,1);if(u>=t)break;let o=u>0?16384:0;v(r,p,0,o,u-o);let D=1+T(p,10,o);for(let A=Math.min(t,u+a);u{n<<=3,s<<=3,I[n]=I[n]<=I[s]?I[n]:I[s],f[n]=f[n]>=f[s]?f[n]:f[s],a[n>>1]+=a[s>>1],m[n>>2]+=m[s>>2]}),tries:t}}if(ee){let e=z(import.meta.url);H(process.argv[2],e,J())}else w.addListener("message",e=>{if(e.type===0)w.postMessage(x(e));else if(e.type===1)w.postMessage(Y(e));else throw new Error("Unknown message type")}); +import{availableParallelism as J}from"node:os";import{fileURLToPath as z}from"node:url";import{isMainThread as ee,parentPort as w}from"node:worker_threads";import{closeSync as K,createWriteStream as V,fstatSync as Q,openSync as $}from"node:fs";import{stdout as j}from"node:process";function h(e,r,t){return e>r?e<=t?e:t:r}function N(e){return e=Math.ceil(e*1),e+=16384-e%16384,h(e,16384,16777216)}function P(e,r){return e=Math.ceil(e/r),e+=16384-e%16384,h(e,16384,16777216)}function T(e,r,t){for(;--t>=0;)if(e[t]===r)return t;return-1}function O(e,r,t,a){let f=1;for(;te.length&&(e=U(e,I+218)),e[0]+=218,e[f+0]=I,e[I+0]=e[1]),f=I}return[e,f]}function C(e=0,r=655360){r=Math.max(219,r);let t=new Int32Array(new SharedArrayBuffer(r<<2));return t[0]=219,t[1]=e,t}function U(e,r=0){let t=e[0];r=Math.max(r,Math.ceil(t*1.618033988749895));let a=new Int32Array(new SharedArrayBuffer(r<<2));for(let f=0;fe[n].length&&(e[n]=U(e[n],o+2),f.push(n)),e[n][0]+=2,e[n][s+0]=o,e[n][o+0]=u,e[n][o+1]=c;else{let l=e[n][o+0];n!==l&&(o=e[n][o+1]),I.push([l,o,u,c])}}s+=1,E+=1}}I.splice(0,m)}while(I.length>0);return f}function Z(e,r,t,a,f="",I){let m=new Array(r.length+1);m[0]=[t,3,0];let i=0,n=!1;do{let[s,R,E]=m[i];if(E>=216){--i;continue}m[i][1]+=1,++m[i][2];let p=e[s][R+0];if(p===0)continue;let D=e[s][p+0];s!==D&&(p=e[s][p+1],s=D),r[i]=E+32,m[++i]=[s,p+2,0];let c=e[s][p+1];c!==0&&(n&&a.write(f),n=!0,I(a,r,i,c))}while(i>=0)}import{Worker as F}from"node:worker_threads";function B(e){let r=new F(e);return r.on("error",t=>{throw t}),r.on("messageerror",t=>{throw t}),r.on("exit",t=>{if(t>1||t<0)throw new Error(`Worker ${r.threadId} exited with code ${t}`)}),r}function b(e,r){return new Promise(t=>{e.once("message",t),e.postMessage(r)})}async function H(e,r,t,a=""){t=h(t,1,256);let f=$(e,"r"),m=Q(f).size,i=P(m,t),n=N(i),s=new SharedArrayBuffer(1e4*t+1<<4),R=new Uint32Array(s,0,1),E=new Int16Array(s),p=new Int16Array(s,2),D=new Uint32Array(s,4),c=new Float64Array(s,8),u=new Array(t),o=[],l=new Array(t);for(let _=0;_{let y=g.id;for(u[y]=g.trie;o.length>0;){let d=await b(S,{type:1,a:y,b:o.pop(),counts:D,maxes:p,mins:E,sums:c,tries:u});for(let L of d.ids)u[L]=d.tries[L]}return o.push(y),S.terminate()})}await Promise.all(l),K(f);let A=V(a,{fd:a.length<1?j.fd:void 0,flags:"a",highWaterMark:1048576}),M=Buffer.allocUnsafe(100);A.write("{"),Z(u,M,o[0],A,", ",X),A.end(`} +`);function X(_,S,g,y){let d=Math.round(c[y<<1]/D[y<<2]);_.write(S.toString("utf8",0,g)),_.write("="),_.write((E[y<<3]/10).toFixed(1)),_.write("/"),_.write((d/10).toFixed(1)),_.write("/"),_.write((p[y<<3]/10).toFixed(1))}}import{readSync as v}from"fs";var k=11*48,W=111*48;function G(e,r,t){return e[r]===45?(++r,r+4>t?k-10*e[r]-e[r+2]:W-100*e[r]-10*e[r+1]-e[r+3]):r+4>t?10*e[r]+e[r+2]-k:100*e[r]+10*e[r+1]+e[r+3]-W}function x({id:e,fd:r,fileSize:t,pageSize:a,chunkSize:f,counts:I,maxes:m,mins:i,page:n,sums:s}){let R=(u,o)=>{i[u<<3]=o,m[u<<3]=o,I[u<<2]=1,s[u<<1]=o},E=(u,o)=>{u<<=3,i[u]=i[u]<=o?i[u]:o,m[u]=m[u]>=o?m[u]:o,++I[u>>1],s[u>>2]+=o},p=Buffer.allocUnsafe(f+16384),D=e*1e4,c=C(e);for(;;){let u=a*Atomics.add(n,0,1);if(u>=t)break;let o=u>0?16384:0;v(r,p,0,o,u-o);let l=T(p,10,o),A=Math.min(t,u+a);for(++l;u{n<<=3,s<<=3,I[n]=I[n]<=I[s]?I[n]:I[s],f[n]=f[n]>=f[s]?f[n]:f[s],a[n>>1]+=a[s>>1],m[n>>2]+=m[s>>2]}),tries:t}}if(ee){let e=z(import.meta.url);H(process.argv[2],e,J())}else w.addListener("message",e=>{if(e.type===0)w.postMessage(x(e));else if(e.type===1)w.postMessage(Y(e));else throw new Error("Unknown message type")}); //# sourceMappingURL=index.mjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index 5ef983d..9f5d97f 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../src/index.ts", "../src/main.ts", "../src/utils/stream.ts", "../src/utils/utf8Trie.ts", "../src/utils/worker.ts", "../src/worker.ts", "../src/utils/parse.ts"], - "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport { RequestType, type Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", (msg: Request) => {\n if (msg.type === RequestType.PROCESS) {\n parentPort!.postMessage(runWorker(msg as ProcessRequest));\n } else if (msg.type === RequestType.MERGE) {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import { closeSync, createWriteStream, fstatSync, openSync, WriteStream } from \"node:fs\";\nimport { stdout } from \"node:process\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { RequestType } from \"./types/request\";\nimport { clamp, getChunkSize, getPageSize } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Open the given file\n const fd = openSync(filePath, \"r\");\n\n // Get file stats\n const fstats = fstatSync(fd);\n const fileSize = fstats.size;\n const pageSize = getPageSize(fileSize, maxWorkers);\n const chunkSize = getChunkSize(pageSize);\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const page = new Uint32Array(valBuf, 0, 1);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: RequestType.PROCESS,\n id: i,\n // I/O\n fd,\n fileSize,\n pageSize,\n chunkSize,\n // Shared memory\n counts,\n maxes,\n mins,\n page,\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[a] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: RequestType.MERGE,\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Close the file\n closeSync(fd);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? stdout.fd : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { Config } from \"../constants/config\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Calculates a chunk size based on a given page size.\n *\n * @param size - The page size.\n *\n * @returns The calculated chunk size.\n */\nexport function getChunkSize(size: number): number {\n // Get size percentage\n size = Math.ceil(size * Config.CHUNK_SIZE_RATIO);\n // Align\n size += Config.SYS_PAGE_SIZE - (size % Config.SYS_PAGE_SIZE);\n // Clamp value\n return clamp(size, Config.CHUNK_SIZE_MIN, Config.CHUNK_SIZE_MAX);\n}\n\n/**\n * Calculates a page size based on a given file size.\n *\n * @param fileSize - The file size.\n * @param workers - The number of workers the file will be split across.\n *\n * @returns The calculated page size.\n */\nexport function getPageSize(fileSize: number, workers: number): number {\n // Divide into workers\n fileSize = Math.ceil(fileSize / workers);\n // Align\n fileSize += Config.SYS_PAGE_SIZE - (fileSize % Config.SYS_PAGE_SIZE);\n // Clamp value\n return clamp(fileSize, Config.PAGE_SIZE_MIN, Config.PAGE_SIZE_MAX);\n}\n\n/**\n * Returns the index of the last occurrence of a \n * specified value in an array, or `-1` if it's not present.\n * \n * @param array - The array to search through.\n * @param searchElement \u2014 The value to locate in the array.\n * @param max \u2014 The array index at which to begin searching backward.\n * \n * @returns the index of the last occurrence, or `-1` if it's not present.\n */\nexport function lastIndexOf(array: ArrayLike, searchElement: T, max: number): number {\n while (--max >= 0) {\n if (array[max] === searchElement) {\n return max;\n }\n }\n return -1;\n}", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown: number[] = [];\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.push(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return grown;\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"node:worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { readSync } from \"fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { lastIndexOf } from \"./utils/stream\";\nimport { Config } from \"./constants/config\";\n\nexport function run({\n id,\n // I/O\n fd,\n fileSize,\n pageSize,\n chunkSize,\n // Shared memory\n counts,\n maxes,\n mins,\n page,\n sums,\n}: ProcessRequest): ProcessResponse {\n const newStation = (index: number, temp: number): void => {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n };\n\n const updateStation = (index: number, temp: number): void => {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n };\n\n // Initialize constants\n const chunk = Buffer.allocUnsafe(chunkSize + Config.SYS_PAGE_SIZE);\n let stations = id * BRC.MAX_STATIONS;\n let trie = createTrie(id);\n\n // For each page\n while (true) {\n\n // Get page start\n let start = pageSize * Atomics.add(page, 0, 1);\n if (start >= fileSize) {\n break;\n }\n\n // Align start with entry\n let bufI = (start > 0) ? Config.SYS_PAGE_SIZE : 0;\n readSync(fd, chunk, 0, bufI, start - bufI);\n let minI = 1 + lastIndexOf(chunk, CharCode.NEWLINE, bufI);\n\n // For each chunk\n for (const end = Math.min(fileSize, start + pageSize); start < end; start += chunkSize) {\n\n // Move incomplete entry to start of buffer\n let maxI = Config.SYS_PAGE_SIZE - bufI + minI;\n chunk.copyWithin(maxI, minI, bufI);\n bufI = Config.SYS_PAGE_SIZE;\n minI = maxI;\n \n // Read the chunk into memory\n maxI = Math.min(chunkSize, end - start);\n maxI = readSync(fd, chunk, bufI, maxI, start);\n\n // For each byte\n for (maxI += bufI; bufI < maxI; ++bufI) {\n \n // If not newline\n if (chunk[bufI] !== CharCode.NEWLINE) {\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 5;\n if (chunk[semI] !== CharCode.SEMICOLON) {\n semI += 1 | (1 + ~(chunk[semI - 1] === CharCode.SEMICOLON));\n }\n\n // Add the station's name to the trie and get leaf\n let leaf: number;\n [trie, leaf] = add(trie, chunk, minI, semI);\n\n // Update next entry's min\n minI = bufI + 1;\n\n // Get temperature\n const temp = parseDouble(chunk, semI + 1, bufI);\n\n // If the station existed\n leaf += TrieNodeProto.VALUE_IDX;\n if (trie[leaf] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf], temp);\n } else {\n // Add the new station's value\n trie[leaf] = ++stations;\n newStation(stations, temp);\n }\n }\n }\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n const ids = mergeLeft(tries, a, b, (ai: number, bi: number): void => {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = mins[ai] <= mins[bi] ? mins[ai] : mins[bi];\n maxes[ai] = maxes[ai] >= maxes[bi] ? maxes[ai] : maxes[bi];\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n });\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], - "mappings": "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", + "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport { RequestType, type Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", (msg: Request) => {\n if (msg.type === RequestType.PROCESS) {\n parentPort!.postMessage(runWorker(msg as ProcessRequest));\n } else if (msg.type === RequestType.MERGE) {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import {\n closeSync,\n createWriteStream,\n fstatSync,\n openSync,\n WriteStream,\n} from \"node:fs\";\nimport { stdout } from \"node:process\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { RequestType } from \"./types/request\";\nimport { clamp, getChunkSize, getPageSize } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Open the given file\n const fd = openSync(filePath, \"r\");\n\n // Get file stats\n const fstats = fstatSync(fd);\n const fileSize = fstats.size;\n const pageSize = getPageSize(fileSize, maxWorkers);\n const chunkSize = getChunkSize(pageSize);\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const page = new Uint32Array(valBuf, 0, 1);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: RequestType.PROCESS,\n id: i,\n // I/O\n fd,\n fileSize,\n pageSize,\n chunkSize,\n // Shared memory\n counts,\n maxes,\n mins,\n page,\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[a] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: RequestType.MERGE,\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Close the file\n closeSync(fd);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? stdout.fd : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { Config } from \"../constants/config\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Calculates a chunk size based on a given page size.\n *\n * @param size - The page size.\n *\n * @returns The calculated chunk size.\n */\nexport function getChunkSize(size: number): number {\n // Get size percentage\n size = Math.ceil(size * Config.CHUNK_SIZE_RATIO);\n // Align\n size += Config.SYS_PAGE_SIZE - (size % Config.SYS_PAGE_SIZE);\n // Clamp value\n return clamp(size, Config.CHUNK_SIZE_MIN, Config.CHUNK_SIZE_MAX);\n}\n\n/**\n * Calculates a page size based on a given file size.\n *\n * @param fileSize - The file size.\n * @param workers - The number of workers the file will be split across.\n *\n * @returns The calculated page size.\n */\nexport function getPageSize(fileSize: number, workers: number): number {\n // Divide into workers\n fileSize = Math.ceil(fileSize / workers);\n // Align\n fileSize += Config.SYS_PAGE_SIZE - (fileSize % Config.SYS_PAGE_SIZE);\n // Clamp value\n return clamp(fileSize, Config.PAGE_SIZE_MIN, Config.PAGE_SIZE_MAX);\n}\n\n/**\n * Returns the index of the last occurrence of a\n * specified value in an array, or `-1` if it's not present.\n *\n * @param array - The array to search through.\n * @param searchElement \u2014 The value to locate in the array.\n * @param max \u2014 The array index at which to begin searching backward.\n *\n * @returns the index of the last occurrence, or `-1` if it's not present.\n */\nexport function lastIndexOf(\n array: ArrayLike,\n searchElement: T,\n max: number,\n): number {\n while (--max >= 0) {\n if (array[max] === searchElement) {\n return max;\n }\n }\n return -1;\n}\n", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown: number[] = [];\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.push(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return grown;\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"node:worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { readSync } from \"fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { lastIndexOf } from \"./utils/stream\";\nimport { Config } from \"./constants/config\";\n\nexport function run({\n id,\n // I/O\n fd,\n fileSize,\n pageSize,\n chunkSize,\n // Shared memory\n counts,\n maxes,\n mins,\n page,\n sums,\n}: ProcessRequest): ProcessResponse {\n const newStation = (index: number, temp: number): void => {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n };\n\n const updateStation = (index: number, temp: number): void => {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n };\n\n // Initialize constants\n const chunk = Buffer.allocUnsafe(chunkSize + Config.SYS_PAGE_SIZE);\n let stations = id * BRC.MAX_STATIONS;\n let trie = createTrie(id);\n\n // For each page\n while (true) {\n // Get page start\n let start = pageSize * Atomics.add(page, 0, 1);\n if (start >= fileSize) {\n break;\n }\n\n // Align start with entry\n let bufI = start > 0 ? Config.SYS_PAGE_SIZE : 0;\n readSync(fd, chunk, 0, bufI, start - bufI);\n let minI = lastIndexOf(chunk, CharCode.NEWLINE, bufI);\n\n // For each chunk\n const end = Math.min(fileSize, start + pageSize);\n for (++minI; start < end; start += chunkSize) {\n // Move incomplete entry to start of buffer\n let maxI = Config.SYS_PAGE_SIZE - bufI + minI;\n chunk.copyWithin(maxI, minI, bufI);\n bufI = Config.SYS_PAGE_SIZE;\n minI = maxI;\n\n // Read the chunk into memory\n maxI = Math.min(chunkSize, end - start);\n maxI = readSync(fd, chunk, bufI, maxI, start);\n\n // For each byte\n for (maxI += bufI; bufI < maxI; ++bufI) {\n // If not newline\n if (chunk[bufI] !== CharCode.NEWLINE) {\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 5;\n if (chunk[semI] !== CharCode.SEMICOLON) {\n semI += 1 | (1 + ~(chunk[semI - 1] === CharCode.SEMICOLON));\n }\n\n // Add the station's name to the trie and get leaf\n let leaf: number;\n [trie, leaf] = add(trie, chunk, minI, semI);\n\n // Update next entry's min\n minI = bufI + 1;\n\n // Get temperature\n const temp = parseDouble(chunk, semI + 1, bufI);\n\n // If the station existed\n leaf += TrieNodeProto.VALUE_IDX;\n if (trie[leaf] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf], temp);\n } else {\n // Add the new station's value\n trie[leaf] = ++stations;\n newStation(stations, temp);\n }\n }\n }\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n const ids = mergeLeft(tries, a, b, (ai: number, bi: number): void => {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = mins[ai] <= mins[bi] ? mins[ai] : mins[bi];\n maxes[ai] = maxes[ai] >= maxes[bi] ? maxes[ai] : maxes[bi];\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n });\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], + "mappings": "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", "names": ["availableParallelism", "fileURLToPath", "isMainThread", "parentPort", "closeSync", "createWriteStream", "fstatSync", "openSync", "stdout", "clamp", "value", "min", "max", "getChunkSize", "size", "getPageSize", "fileSize", "workers", "lastIndexOf", "array", "searchElement", "add", "trie", "key", "min", "max", "index", "child", "grow", "createTrie", "id", "size", "trie", "grow", "minSize", "length", "next", "i", "mergeLeft", "tries", "at", "bt", "mergeFn", "grown", "queue", "Q", "q", "ai", "bi", "bvi", "avi", "bn", "ri", "rt", "li", "lt", "print", "key", "trieIndex", "stream", "separator", "callbackFn", "stack", "top", "tail", "trieI", "childPtr", "numChild", "childI", "childTrieI", "valueIndex", "Worker", "createWorker", "workerPath", "worker", "err", "code", "exec", "req", "resolve", "run", "filePath", "workerPath", "maxWorkers", "outPath", "clamp", "fd", "openSync", "fileSize", "fstatSync", "pageSize", "getPageSize", "chunkSize", "getChunkSize", "valBuf", "page", "mins", "maxes", "counts", "sums", "tries", "unmerged", "tasks", "i", "worker", "createWorker", "exec", "res", "a", "id", "closeSync", "out", "createWriteStream", "stdout", "buffer", "print", "printStation", "stream", "name", "nameLen", "vi", "avg", "readSync", "CHAR_ZERO_11", "CHAR_ZERO_111", "parseDouble", "b", "min", "max", "run", "id", "fd", "fileSize", "pageSize", "chunkSize", "counts", "maxes", "mins", "page", "sums", "newStation", "index", "temp", "updateStation", "chunk", "stations", "trie", "createTrie", "start", "bufI", "readSync", "minI", "lastIndexOf", "end", "maxI", "semI", "leaf", "add", "parseDouble", "merge", "a", "b", "tries", "mergeLeft", "ai", "bi", "isMainThread", "workerPath", "fileURLToPath", "run", "availableParallelism", "parentPort", "msg", "merge"] } diff --git a/src/main/nodejs/havelessbemore/src/constants/config.ts b/src/main/nodejs/havelessbemore/src/constants/config.ts index ee0a277..907729c 100644 --- a/src/main/nodejs/havelessbemore/src/constants/config.ts +++ b/src/main/nodejs/havelessbemore/src/constants/config.ts @@ -1,48 +1,68 @@ /* eslint-disable @typescript-eslint/no-duplicate-enum-values */ +export const enum Mem { + KB = 1024, + KB_2 = 2048, + KB_4 = 4096, + KB_8 = 8192, + KB_16 = 16384, + MB = 1048576, + MB_2 = 2097152, + MB_4 = 4194304, + MB_8 = 8388608, + MB_16 = 16777216, + MB_32 = 33554432, + MB_64 = 67108864, + MB_128 = 134217728, + MB_256 = 268435456, + MB_512 = 536870912, + GB = 1073741824, + GB_2 = 2147483648, +} + export const enum Config { /** * The system's page size (`getconf PAGE_SIZE`). */ - SYS_PAGE_SIZE = 16384, // 16 KiB, + SYS_PAGE_SIZE = Mem.KB_16, /** * The minimum value in bytes for a chunk size. - * + * * Should ideally be a multiple of {@link SYS_PAGE_SIZE} */ CHUNK_SIZE_MIN = SYS_PAGE_SIZE, /** * The maximum value in bytes for a chunk size. - * + * * Should ideally be a multiple of {@link SYS_PAGE_SIZE} */ - CHUNK_SIZE_MAX = 16777216, // 16 MiB + CHUNK_SIZE_MAX = Mem.MB_16, /** * The ratio of the page size for calculating chunk size. */ - CHUNK_SIZE_RATIO = 0.00390625, + CHUNK_SIZE_RATIO = 1, /** * The `highWaterMark` for write streams. */ - HIGH_WATER_MARK_OUT = 1048576, // 1 MiB + HIGH_WATER_MARK_OUT = Mem.MB, /** * The minimum value in bytes for a page size. - * + * * Should ideally be a multiple of {@link SYS_PAGE_SIZE} */ PAGE_SIZE_MIN = SYS_PAGE_SIZE, /** * The maximum value in bytes for a page size. - * + * * Should ideally be a multiple of {@link SYS_PAGE_SIZE} */ - PAGE_SIZE_MAX = 4294967296, // 4 GiB + PAGE_SIZE_MAX = Mem.MB_16, /** * The minimum number of web workers (inclusive). diff --git a/src/main/nodejs/havelessbemore/src/main.ts b/src/main/nodejs/havelessbemore/src/main.ts index 2d34df2..a7359dc 100644 --- a/src/main/nodejs/havelessbemore/src/main.ts +++ b/src/main/nodejs/havelessbemore/src/main.ts @@ -1,4 +1,10 @@ -import { closeSync, createWriteStream, fstatSync, openSync, WriteStream } from "node:fs"; +import { + closeSync, + createWriteStream, + fstatSync, + openSync, + WriteStream, +} from "node:fs"; import { stdout } from "node:process"; import type { MergeRequest } from "./types/mergeRequest"; diff --git a/src/main/nodejs/havelessbemore/src/utils/stream.ts b/src/main/nodejs/havelessbemore/src/utils/stream.ts index 31fa3d2..0576ad6 100644 --- a/src/main/nodejs/havelessbemore/src/utils/stream.ts +++ b/src/main/nodejs/havelessbemore/src/utils/stream.ts @@ -47,20 +47,24 @@ export function getPageSize(fileSize: number, workers: number): number { } /** - * Returns the index of the last occurrence of a + * Returns the index of the last occurrence of a * specified value in an array, or `-1` if it's not present. - * + * * @param array - The array to search through. * @param searchElement — The value to locate in the array. * @param max — The array index at which to begin searching backward. - * + * * @returns the index of the last occurrence, or `-1` if it's not present. */ -export function lastIndexOf(array: ArrayLike, searchElement: T, max: number): number { +export function lastIndexOf( + array: ArrayLike, + searchElement: T, + max: number, +): number { while (--max >= 0) { if (array[max] === searchElement) { return max; } } return -1; -} \ No newline at end of file +} diff --git a/src/main/nodejs/havelessbemore/src/worker.ts b/src/main/nodejs/havelessbemore/src/worker.ts index b17f271..733d3f0 100644 --- a/src/main/nodejs/havelessbemore/src/worker.ts +++ b/src/main/nodejs/havelessbemore/src/worker.ts @@ -47,8 +47,8 @@ export function run({ let trie = createTrie(id); // For each page + // eslint-disable-next-line no-constant-condition while (true) { - // Get page start let start = pageSize * Atomics.add(page, 0, 1); if (start >= fileSize) { @@ -56,26 +56,25 @@ export function run({ } // Align start with entry - let bufI = (start > 0) ? Config.SYS_PAGE_SIZE : 0; + let bufI = start > 0 ? Config.SYS_PAGE_SIZE : 0; readSync(fd, chunk, 0, bufI, start - bufI); - let minI = 1 + lastIndexOf(chunk, CharCode.NEWLINE, bufI); + let minI = lastIndexOf(chunk, CharCode.NEWLINE, bufI); // For each chunk - for (const end = Math.min(fileSize, start + pageSize); start < end; start += chunkSize) { - + const end = Math.min(fileSize, start + pageSize); + for (++minI; start < end; start += chunkSize) { // Move incomplete entry to start of buffer let maxI = Config.SYS_PAGE_SIZE - bufI + minI; chunk.copyWithin(maxI, minI, bufI); bufI = Config.SYS_PAGE_SIZE; minI = maxI; - + // Read the chunk into memory maxI = Math.min(chunkSize, end - start); maxI = readSync(fd, chunk, bufI, maxI, start); // For each byte for (maxI += bufI; bufI < maxI; ++bufI) { - // If not newline if (chunk[bufI] !== CharCode.NEWLINE) { continue; From 9e8604ad288cbf016c3f4e8c1f355159ef06656c Mon Sep 17 00:00:00 2001 From: havelessbemore Date: Thu, 30 May 2024 23:09:28 -0400 Subject: [PATCH 68/69] Update benchmark results --- src/main/nodejs/havelessbemore/README.md | 4 ++-- src/main/nodejs/havelessbemore/dist/index.mjs.map | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/nodejs/havelessbemore/README.md b/src/main/nodejs/havelessbemore/README.md index 633acb7..d33e9d7 100644 --- a/src/main/nodejs/havelessbemore/README.md +++ b/src/main/nodejs/havelessbemore/README.md @@ -15,8 +15,8 @@ ### Results - Min: 11.1s -- Avg: 11.9s -- Max: 12.1s +- Avg: 11.6s +- Max: 12.0s - Samples: 10 runs, 5s apart #### Specs: diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map index 9f5d97f..56bcadb 100644 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ b/src/main/nodejs/havelessbemore/dist/index.mjs.map @@ -1,7 +1,7 @@ { "version": 3, "sources": ["../src/index.ts", "../src/main.ts", "../src/utils/stream.ts", "../src/utils/utf8Trie.ts", "../src/utils/worker.ts", "../src/worker.ts", "../src/utils/parse.ts"], - "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport { RequestType, type Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", (msg: Request) => {\n if (msg.type === RequestType.PROCESS) {\n parentPort!.postMessage(runWorker(msg as ProcessRequest));\n } else if (msg.type === RequestType.MERGE) {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import {\n closeSync,\n createWriteStream,\n fstatSync,\n openSync,\n WriteStream,\n} from \"node:fs\";\nimport { stdout } from \"node:process\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { RequestType } from \"./types/request\";\nimport { clamp, getChunkSize, getPageSize } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Open the given file\n const fd = openSync(filePath, \"r\");\n\n // Get file stats\n const fstats = fstatSync(fd);\n const fileSize = fstats.size;\n const pageSize = getPageSize(fileSize, maxWorkers);\n const chunkSize = getChunkSize(pageSize);\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const page = new Uint32Array(valBuf, 0, 1);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: RequestType.PROCESS,\n id: i,\n // I/O\n fd,\n fileSize,\n pageSize,\n chunkSize,\n // Shared memory\n counts,\n maxes,\n mins,\n page,\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[a] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: RequestType.MERGE,\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Close the file\n closeSync(fd);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? stdout.fd : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { Config } from \"../constants/config\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Calculates a chunk size based on a given page size.\n *\n * @param size - The page size.\n *\n * @returns The calculated chunk size.\n */\nexport function getChunkSize(size: number): number {\n // Get size percentage\n size = Math.ceil(size * Config.CHUNK_SIZE_RATIO);\n // Align\n size += Config.SYS_PAGE_SIZE - (size % Config.SYS_PAGE_SIZE);\n // Clamp value\n return clamp(size, Config.CHUNK_SIZE_MIN, Config.CHUNK_SIZE_MAX);\n}\n\n/**\n * Calculates a page size based on a given file size.\n *\n * @param fileSize - The file size.\n * @param workers - The number of workers the file will be split across.\n *\n * @returns The calculated page size.\n */\nexport function getPageSize(fileSize: number, workers: number): number {\n // Divide into workers\n fileSize = Math.ceil(fileSize / workers);\n // Align\n fileSize += Config.SYS_PAGE_SIZE - (fileSize % Config.SYS_PAGE_SIZE);\n // Clamp value\n return clamp(fileSize, Config.PAGE_SIZE_MIN, Config.PAGE_SIZE_MAX);\n}\n\n/**\n * Returns the index of the last occurrence of a\n * specified value in an array, or `-1` if it's not present.\n *\n * @param array - The array to search through.\n * @param searchElement \u2014 The value to locate in the array.\n * @param max \u2014 The array index at which to begin searching backward.\n *\n * @returns the index of the last occurrence, or `-1` if it's not present.\n */\nexport function lastIndexOf(\n array: ArrayLike,\n searchElement: T,\n max: number,\n): number {\n while (--max >= 0) {\n if (array[max] === searchElement) {\n return max;\n }\n }\n return -1;\n}\n", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown: number[] = [];\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.push(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return grown;\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"node:worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { readSync } from \"fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { lastIndexOf } from \"./utils/stream\";\nimport { Config } from \"./constants/config\";\n\nexport function run({\n id,\n // I/O\n fd,\n fileSize,\n pageSize,\n chunkSize,\n // Shared memory\n counts,\n maxes,\n mins,\n page,\n sums,\n}: ProcessRequest): ProcessResponse {\n const newStation = (index: number, temp: number): void => {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n };\n\n const updateStation = (index: number, temp: number): void => {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n };\n\n // Initialize constants\n const chunk = Buffer.allocUnsafe(chunkSize + Config.SYS_PAGE_SIZE);\n let stations = id * BRC.MAX_STATIONS;\n let trie = createTrie(id);\n\n // For each page\n while (true) {\n // Get page start\n let start = pageSize * Atomics.add(page, 0, 1);\n if (start >= fileSize) {\n break;\n }\n\n // Align start with entry\n let bufI = start > 0 ? Config.SYS_PAGE_SIZE : 0;\n readSync(fd, chunk, 0, bufI, start - bufI);\n let minI = lastIndexOf(chunk, CharCode.NEWLINE, bufI);\n\n // For each chunk\n const end = Math.min(fileSize, start + pageSize);\n for (++minI; start < end; start += chunkSize) {\n // Move incomplete entry to start of buffer\n let maxI = Config.SYS_PAGE_SIZE - bufI + minI;\n chunk.copyWithin(maxI, minI, bufI);\n bufI = Config.SYS_PAGE_SIZE;\n minI = maxI;\n\n // Read the chunk into memory\n maxI = Math.min(chunkSize, end - start);\n maxI = readSync(fd, chunk, bufI, maxI, start);\n\n // For each byte\n for (maxI += bufI; bufI < maxI; ++bufI) {\n // If not newline\n if (chunk[bufI] !== CharCode.NEWLINE) {\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 5;\n if (chunk[semI] !== CharCode.SEMICOLON) {\n semI += 1 | (1 + ~(chunk[semI - 1] === CharCode.SEMICOLON));\n }\n\n // Add the station's name to the trie and get leaf\n let leaf: number;\n [trie, leaf] = add(trie, chunk, minI, semI);\n\n // Update next entry's min\n minI = bufI + 1;\n\n // Get temperature\n const temp = parseDouble(chunk, semI + 1, bufI);\n\n // If the station existed\n leaf += TrieNodeProto.VALUE_IDX;\n if (trie[leaf] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf], temp);\n } else {\n // Add the new station's value\n trie[leaf] = ++stations;\n newStation(stations, temp);\n }\n }\n }\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n const ids = mergeLeft(tries, a, b, (ai: number, bi: number): void => {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = mins[ai] <= mins[bi] ? mins[ai] : mins[bi];\n maxes[ai] = maxes[ai] >= maxes[bi] ? maxes[ai] : maxes[bi];\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n });\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], - "mappings": "AAAA,OAAS,wBAAAA,MAA4B,UACrC,OAAS,iBAAAC,MAAqB,WAC9B,OAAS,gBAAAC,GAAc,cAAAC,MAAkB,sBCFzC,OACE,aAAAC,EACA,qBAAAC,EACA,aAAAC,EACA,YAAAC,MAEK,UACP,OAAS,UAAAC,MAAc,eCIhB,SAASC,EAAMC,EAAeC,EAAaC,EAAqB,CACrE,OAAOF,EAAQC,EAAOD,GAASE,EAAMF,EAAQE,EAAOD,CACtD,CASO,SAASE,EAAaC,EAAsB,CAEjD,OAAAA,EAAO,KAAK,KAAKA,EAAO,CAAuB,EAE/CA,GAAQ,MAAwBA,EAAO,MAEhCL,EAAMK,gBAAkD,CACjE,CAUO,SAASC,EAAYC,EAAkBC,EAAyB,CAErE,OAAAD,EAAW,KAAK,KAAKA,EAAWC,CAAO,EAEvCD,GAAY,MAAwBA,EAAW,MAExCP,EAAMO,gBAAoD,CACnE,CAYO,SAASE,EACdC,EACAC,EACAR,EACQ,CACR,KAAO,EAAEA,GAAO,GACd,GAAIO,EAAMP,CAAG,IAAMQ,EACjB,OAAOR,EAGX,MAAO,EACT,CC1DO,SAASS,EACdC,EACAC,EACAC,EACAC,EACsB,CACtB,IAAIC,IACJ,KAAOF,EAAMC,GAAK,CAChBC,GACE,EACA,GAAwBH,EAAIC,GAAK,EAAI,IACvC,IAAIG,EAAQL,EAAKI,EAAQ,CAAwB,EAC7CC,IAAU,IAEZA,EAAQL,GAAuB,EAC3BK,EAAQ,IAAoBL,EAAK,SACnCA,EAAOM,EAAKN,EAAMK,EAAQ,GAAiB,GAE7CL,GAAuB,GAAK,IAE5BA,EAAKI,EAAQ,CAAwB,EAAIC,EAEzCL,EAAKK,EAAQ,CAAoB,EAAIL,GAAqB,GAE5DI,EAAQC,CACV,CAEA,MAAO,CAACL,EAAMI,CAAK,CACrB,CA8BO,SAASG,EAAWC,EAAK,EAAGC,SAAsC,CACvEA,EAAO,KAAK,QAAmBA,CAAI,EACnC,IAAMC,EAAO,IAAI,WAAW,IAAI,kBAAkBD,GAAQ,CAAC,CAAC,EAC5D,OAAAC,GAAuB,EAAI,IAC3BA,GAAqB,EAAIF,EAClBE,CACT,CAEO,SAASC,EAAKD,EAAkBE,EAAU,EAAe,CAC9D,IAAMC,EAASH,GAAuB,EACtCE,EAAU,KAAK,IAAIA,EAAS,KAAK,KAAKC,EAAS,iBAAkB,CAAC,EAClE,IAAMC,EAAO,IAAI,WAAW,IAAI,kBAAkBF,GAAW,CAAC,CAAC,EAC/D,QAASG,EAAI,EAAGA,EAAIF,EAAQ,EAAEE,EAC5BD,EAAKC,CAAC,EAAIL,EAAKK,CAAC,EAElB,OAAOD,CACT,CAEO,SAASE,EACdC,EACAC,EACAC,EACAC,EACU,CACV,IAAMC,EAAkB,CAAC,EACnBC,EAA4C,CAChD,CAACJ,IAAwBC,GAAsB,CACjD,EAEA,EAAG,CACD,IAAMI,EAAID,EAAM,OAChB,QAASE,EAAI,EAAGA,EAAID,EAAG,EAAEC,EAAG,CAE1B,GAAI,CAACN,EAAIO,EAAIN,EAAIO,CAAE,EAAIJ,EAAME,CAAC,EAGxBG,EAAMV,EAAME,CAAE,EAAEO,EAAK,CAAuB,EAClD,GAAIC,IAAQ,EAAW,CAErB,IAAMC,EAAMX,EAAMC,CAAE,EAAEO,EAAK,CAAuB,EAC9CG,IAAQ,EACVR,EAAQQ,EAAKD,CAAG,EAEhBV,EAAMC,CAAE,EAAEO,EAAK,CAAuB,EAAIE,CAE9C,CAGAF,GAAM,EACNC,GAAM,EAGN,IAAMG,EAAKH,EAAK,IAChB,KAAOA,EAAKG,GAAI,CAEd,IAAIC,EAAKb,EAAME,CAAE,EAAEO,EAAK,CAAwB,EAChD,GAAII,IAAO,EAAW,CAEpB,IAAMC,EAAKd,EAAME,CAAE,EAAEW,EAAK,CAAoB,EAC1CX,IAAOY,IACTD,EAAKb,EAAME,CAAE,EAAEW,EAAK,CAAyB,GAI/C,IAAIE,EAAKf,EAAMC,CAAE,EAAEO,EAAK,CAAwB,EAChD,GAAIO,IAAO,EAETA,EAAKf,EAAMC,CAAE,GAAoB,EAC7Bc,EAAK,EAAwBf,EAAMC,CAAE,EAAE,SACzCD,EAAMC,CAAE,EAAIP,EAAKM,EAAMC,CAAE,EAAGc,EAAK,CAAqB,EACtDX,EAAM,KAAKH,CAAE,GAEfD,EAAMC,CAAE,GAAoB,GAAK,EAEjCD,EAAMC,CAAE,EAAEO,EAAK,CAAwB,EAAIO,EAE3Cf,EAAMC,CAAE,EAAEc,EAAK,CAAwB,EAAID,EAC3Cd,EAAMC,CAAE,EAAEc,EAAK,CAAyB,EAAIF,MACvC,CAEL,IAAMG,EAAKhB,EAAMC,CAAE,EAAEc,EAAK,CAAoB,EAC1Cd,IAAOe,IACTD,EAAKf,EAAMC,CAAE,EAAEc,EAAK,CAAyB,GAG/CV,EAAM,KAAK,CAACW,EAAID,EAAID,EAAID,CAAE,CAAC,CAC7B,CACF,CAGAL,GAAM,EACNC,GAAM,CACR,CACF,CACAJ,EAAM,OAAO,EAAGC,CAAC,CACnB,OAASD,EAAM,OAAS,GACxB,OAAOD,CACT,CAEO,SAASa,EACdjB,EACAkB,EACAC,EACAC,EACAC,EAAY,GACZC,EAMM,CACN,IAAMC,EAAQ,IAAI,MAAgCL,EAAI,OAAS,CAAC,EAChEK,EAAM,CAAC,EAAI,CAACJ,EAAW,EAAiD,CAAC,EAEzE,IAAIK,EAAM,EACNC,EAAO,GACX,EAAG,CAED,GAAI,CAACC,EAAOC,EAAUC,CAAQ,EAAIL,EAAMC,CAAG,EAG3C,GAAII,GAAY,IAA4B,CAC1C,EAAEJ,EACF,QACF,CAGAD,EAAMC,CAAG,EAAE,CAAC,GAAK,EACjB,EAAED,EAAMC,CAAG,EAAE,CAAC,EAGd,IAAIK,EAAS7B,EAAM0B,CAAK,EAAEC,EAAW,CAAwB,EAC7D,GAAIE,IAAW,EACb,SAIF,IAAMC,EAAa9B,EAAM0B,CAAK,EAAEG,EAAS,CAAoB,EACzDH,IAAUI,IACZD,EAAS7B,EAAM0B,CAAK,EAAEG,EAAS,CAAyB,EACxDH,EAAQI,GAIVZ,EAAIM,CAAG,EAAII,EAAW,GACtBL,EAAM,EAAEC,CAAG,EAAI,CAACE,EAAOG,EAAS,EAA4B,CAAC,EAG7D,IAAME,EAAa/B,EAAM0B,CAAK,EAAEG,EAAS,CAAuB,EAC5DE,IAAe,IAEbN,GACFL,EAAO,MAAMC,CAAS,EAExBI,EAAO,GACPH,EAAWF,EAAQF,EAAKM,EAAKO,CAAU,EAE3C,OAASP,GAAO,EAClB,CCpOA,OAAS,UAAAQ,MAAc,sBAShB,SAASC,EAAaC,EAA4B,CACvD,IAAMC,EAAS,IAAIH,EAAOE,CAAU,EACpC,OAAAC,EAAO,GAAG,QAAUC,GAAQ,CAC1B,MAAMA,CACR,CAAC,EACDD,EAAO,GAAG,eAAiBC,GAAQ,CACjC,MAAMA,CACR,CAAC,EACDD,EAAO,GAAG,OAASE,GAAS,CAC1B,GAAIA,EAAO,GAAKA,EAAO,EACrB,MAAM,IAAI,MAAM,UAAUF,EAAO,QAAQ,qBAAqBE,CAAI,EAAE,CAExE,CAAC,EACMF,CACT,CAUO,SAASG,EAAeH,EAAgBI,EAAwB,CACrE,OAAO,IAAI,QAAcC,GAAY,CACnCL,EAAO,KAAK,UAAWK,CAAO,EAC9BL,EAAO,YAAYI,CAAG,CACxB,CAAC,CACH,CHjBA,eAAsBE,EACpBC,EACAC,EACAC,EACAC,EAAU,GACK,CAEfD,EAAaE,EAAMF,OAAkD,EAGrE,IAAMG,EAAKC,EAASN,EAAU,GAAG,EAI3BO,EADSC,EAAUH,CAAE,EACH,KAClBI,EAAWC,EAAYH,EAAUL,CAAU,EAC3CS,EAAYC,EAAaH,CAAQ,EAGjCI,EAAS,IAAI,kBAChB,IAAmBX,EAAa,GAAM,CACzC,EACMY,EAAO,IAAI,YAAYD,EAAQ,EAAG,CAAC,EACnCE,EAAO,IAAI,WAAWF,CAAM,EAC5BG,EAAQ,IAAI,WAAWH,EAAQ,CAAC,EAChCI,EAAS,IAAI,YAAYJ,EAAQ,CAAC,EAClCK,EAAO,IAAI,aAAaL,EAAQ,CAAC,EACjCM,EAAQ,IAAI,MAAkBjB,CAAU,EAGxCkB,EAAqB,CAAC,EACtBC,EAAQ,IAAI,MAAwBnB,CAAU,EACpD,QAASoB,EAAI,EAAGA,EAAIpB,EAAY,EAAEoB,EAAG,CAEnC,IAAMC,EAASC,EAAavB,CAAU,EAEtCoB,EAAMC,CAAC,EAAIG,EAAsCF,EAAQ,CACvD,OACA,GAAID,EAEJ,GAAAjB,EACA,SAAAE,EACA,SAAAE,EACA,UAAAE,EAEA,OAAAM,EACA,MAAAD,EACA,KAAAD,EACA,KAAAD,EACA,KAAAI,CACF,CAAC,EAAE,KAAK,MAAOQ,GAAQ,CAErB,IAAMC,EAAID,EAAI,GAGd,IAFAP,EAAMQ,CAAC,EAAID,EAAI,KAERN,EAAS,OAAS,GAAG,CAC1B,IAAMM,EAAM,MAAMD,EAAkCF,EAAQ,CAC1D,OACA,EAAAI,EACA,EAAGP,EAAS,IAAI,EAChB,OAAAH,EACA,MAAAD,EACA,KAAAD,EACA,KAAAG,EACA,MAAAC,CACF,CAAC,EAED,QAAWS,KAAMF,EAAI,IACnBP,EAAMS,CAAE,EAAIF,EAAI,MAAME,CAAE,CAE5B,CACA,OAAAR,EAAS,KAAKO,CAAC,EAERJ,EAAO,UAAU,CAC1B,CAAC,CACH,CAGA,MAAM,QAAQ,IAAIF,CAAK,EAGvBQ,EAAUxB,CAAE,EAGZ,IAAMyB,EAAMC,EAAkB5B,EAAS,CACrC,GAAIA,EAAQ,OAAS,EAAI6B,EAAO,GAAK,OACrC,MAAO,IACP,qBACF,CAAC,EACKC,EAAS,OAAO,eAAoC,EAC1DH,EAAI,MAAM,GAAG,EACbI,EAAMf,EAAOc,EAAQb,EAAS,CAAC,EAAGU,EAAK,KAAMK,CAAY,EACzDL,EAAI,IAAI;AAAA,CAAK,EAEb,SAASK,EACPC,EACAC,EACAC,EACAC,EACM,CACN,IAAMC,EAAM,KAAK,MAAMtB,EAAKqB,GAAM,CAAC,EAAItB,EAAOsB,GAAM,CAAC,CAAC,EACtDH,EAAO,MAAMC,EAAK,SAAS,OAAQ,EAAGC,CAAO,CAAC,EAC9CF,EAAO,MAAM,GAAG,EAChBA,EAAO,OAAOrB,EAAKwB,GAAM,CAAC,EAAI,IAAI,QAAQ,CAAC,CAAC,EAC5CH,EAAO,MAAM,GAAG,EAChBA,EAAO,OAAOI,EAAM,IAAI,QAAQ,CAAC,CAAC,EAClCJ,EAAO,MAAM,GAAG,EAChBA,EAAO,OAAOpB,EAAMuB,GAAM,CAAC,EAAI,IAAI,QAAQ,CAAC,CAAC,CAC/C,CACF,CIlIA,OAAS,YAAAE,MAAgB,KCElB,IAAMC,EAAe,GAAK,GACpBC,EAAgB,IAAM,GAO5B,SAASC,EAAYC,EAAWC,EAAaC,EAAqB,CACvE,OAAIF,EAAEC,CAAG,IAAM,IACb,EAAEA,EACKA,EAAM,EAAIC,EACbL,EAAe,GAAKG,EAAEC,CAAG,EAAID,EAAEC,EAAM,CAAC,EACtCH,EAAgB,IAAME,EAAEC,CAAG,EAAI,GAAKD,EAAEC,EAAM,CAAC,EAAID,EAAEC,EAAM,CAAC,GAEzDA,EAAM,EAAIC,EACb,GAAKF,EAAEC,CAAG,EAAID,EAAEC,EAAM,CAAC,EAAIJ,EAC3B,IAAMG,EAAEC,CAAG,EAAI,GAAKD,EAAEC,EAAM,CAAC,EAAID,EAAEC,EAAM,CAAC,EAAIH,CACpD,CDNO,SAASK,EAAI,CAClB,GAAAC,EAEA,GAAAC,EACA,SAAAC,EACA,SAAAC,EACA,UAAAC,EAEA,OAAAC,EACA,MAAAC,EACA,KAAAC,EACA,KAAAC,EACA,KAAAC,CACF,EAAoC,CAClC,IAAMC,EAAa,CAACC,EAAeC,IAAuB,CACxDL,EAAKI,GAAS,CAAC,EAAIC,EACnBN,EAAMK,GAAS,CAAC,EAAIC,EACpBP,EAAOM,GAAS,CAAC,EAAI,EACrBF,EAAKE,GAAS,CAAC,EAAIC,CACrB,EAEMC,EAAgB,CAACF,EAAeC,IAAuB,CAC3DD,IAAU,EACVJ,EAAKI,CAAK,EAAIJ,EAAKI,CAAK,GAAKC,EAAOL,EAAKI,CAAK,EAAIC,EAClDN,EAAMK,CAAK,EAAIL,EAAMK,CAAK,GAAKC,EAAON,EAAMK,CAAK,EAAIC,EACrD,EAAEP,EAAOM,GAAS,CAAC,EACnBF,EAAKE,GAAS,CAAC,GAAKC,CACtB,EAGME,EAAQ,OAAO,YAAYV,EAAY,KAAoB,EAC7DW,EAAWf,EAAK,IAChBgB,EAAOC,EAAWjB,CAAE,EAGxB,OAAa,CAEX,IAAIkB,EAAQf,EAAW,QAAQ,IAAIK,EAAM,EAAG,CAAC,EAC7C,GAAIU,GAAShB,EACX,MAIF,IAAIiB,EAAOD,EAAQ,QAA2B,EAC9CE,EAASnB,EAAIa,EAAO,EAAGK,EAAMD,EAAQC,CAAI,EACzC,IAAIE,EAAOC,EAAYR,KAAyBK,CAAI,EAG9CI,EAAM,KAAK,IAAIrB,EAAUgB,EAAQf,CAAQ,EAC/C,IAAK,EAAEkB,EAAMH,EAAQK,EAAKL,GAASd,EAAW,CAE5C,IAAIoB,EAAO,MAAuBL,EAAOE,EAUzC,IATAP,EAAM,WAAWU,EAAMH,EAAMF,CAAI,EACjCA,EAAO,MACPE,EAAOG,EAGPA,EAAO,KAAK,IAAIpB,EAAWmB,EAAML,CAAK,EACtCM,EAAOJ,EAASnB,EAAIa,EAAOK,EAAMK,EAAMN,CAAK,EAGvCM,GAAQL,EAAMA,EAAOK,EAAM,EAAEL,EAAM,CAEtC,GAAIL,EAAMK,CAAI,IAAM,GAClB,SAIF,IAAIM,EAAON,EAAO,EACdL,EAAMW,CAAI,IAAM,KAClBA,GAAQ,EAAK,EAAI,EAAEX,EAAMW,EAAO,CAAC,IAAM,KAIzC,IAAIC,EACJ,CAACV,EAAMU,CAAI,EAAIC,EAAIX,EAAMF,EAAOO,EAAMI,CAAI,EAG1CJ,EAAOF,EAAO,EAGd,IAAMP,EAAOgB,EAAYd,EAAOW,EAAO,EAAGN,CAAI,EAG9CO,GAAQ,EACJV,EAAKU,CAAI,IAAM,EAEjBb,EAAcG,EAAKU,CAAI,EAAGd,CAAI,GAG9BI,EAAKU,CAAI,EAAI,EAAEX,EACfL,EAAWK,EAAUH,CAAI,EAE7B,CACF,CACF,CAEA,MAAO,CAAE,GAAAZ,EAAI,KAAAgB,CAAK,CACpB,CAEO,SAASa,EAAM,CACpB,EAAAC,EACA,EAAAC,EACA,MAAAC,EACA,OAAA3B,EACA,MAAAC,EACA,KAAAC,EACA,KAAAE,CACF,EAAgC,CAS9B,MAAO,CAAE,IARGwB,EAAUD,EAAOF,EAAGC,EAAG,CAACG,EAAYC,IAAqB,CACnED,IAAO,EACPC,IAAO,EACP5B,EAAK2B,CAAE,EAAI3B,EAAK2B,CAAE,GAAK3B,EAAK4B,CAAE,EAAI5B,EAAK2B,CAAE,EAAI3B,EAAK4B,CAAE,EACpD7B,EAAM4B,CAAE,EAAI5B,EAAM4B,CAAE,GAAK5B,EAAM6B,CAAE,EAAI7B,EAAM4B,CAAE,EAAI5B,EAAM6B,CAAE,EACzD9B,EAAO6B,GAAM,CAAC,GAAK7B,EAAO8B,GAAM,CAAC,EACjC1B,EAAKyB,GAAM,CAAC,GAAKzB,EAAK0B,GAAM,CAAC,CAC/B,CAAC,EACa,MAAAH,CAAM,CACtB,CLzHA,GAAII,GAAc,CAChB,IAAMC,EAAaC,EAAc,YAAY,GAAG,EAChDC,EAAQ,QAAQ,KAAK,CAAC,EAAGF,EAAYG,EAAqB,CAAC,CAC7D,MACEC,EAAY,YAAY,UAAYC,GAAiB,CACnD,GAAIA,EAAI,OAAS,EACfD,EAAY,YAAYF,EAAUG,CAAqB,CAAC,UAC/CA,EAAI,OAAS,EACtBD,EAAY,YAAYE,EAAMD,CAAmB,CAAC,MAElD,OAAM,IAAI,MAAM,sBAAsB,CAE1C,CAAC", + "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport { RequestType, type Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", (msg: Request) => {\n if (msg.type === RequestType.PROCESS) {\n parentPort!.postMessage(runWorker(msg as ProcessRequest));\n } else if (msg.type === RequestType.MERGE) {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import {\n closeSync,\n createWriteStream,\n fstatSync,\n openSync,\n WriteStream,\n} from \"node:fs\";\nimport { stdout } from \"node:process\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { RequestType } from \"./types/request\";\nimport { clamp, getChunkSize, getPageSize } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Open the given file\n const fd = openSync(filePath, \"r\");\n\n // Get file stats\n const fstats = fstatSync(fd);\n const fileSize = fstats.size;\n const pageSize = getPageSize(fileSize, maxWorkers);\n const chunkSize = getChunkSize(pageSize);\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const page = new Uint32Array(valBuf, 0, 1);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: RequestType.PROCESS,\n id: i,\n // I/O\n fd,\n fileSize,\n pageSize,\n chunkSize,\n // Shared memory\n counts,\n maxes,\n mins,\n page,\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[a] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: RequestType.MERGE,\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Close the file\n closeSync(fd);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? stdout.fd : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { Config } from \"../constants/config\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Calculates a chunk size based on a given page size.\n *\n * @param size - The page size.\n *\n * @returns The calculated chunk size.\n */\nexport function getChunkSize(size: number): number {\n // Get size percentage\n size = Math.ceil(size * Config.CHUNK_SIZE_RATIO);\n // Align\n size += Config.SYS_PAGE_SIZE - (size % Config.SYS_PAGE_SIZE);\n // Clamp value\n return clamp(size, Config.CHUNK_SIZE_MIN, Config.CHUNK_SIZE_MAX);\n}\n\n/**\n * Calculates a page size based on a given file size.\n *\n * @param fileSize - The file size.\n * @param workers - The number of workers the file will be split across.\n *\n * @returns The calculated page size.\n */\nexport function getPageSize(fileSize: number, workers: number): number {\n // Divide into workers\n fileSize = Math.ceil(fileSize / workers);\n // Align\n fileSize += Config.SYS_PAGE_SIZE - (fileSize % Config.SYS_PAGE_SIZE);\n // Clamp value\n return clamp(fileSize, Config.PAGE_SIZE_MIN, Config.PAGE_SIZE_MAX);\n}\n\n/**\n * Returns the index of the last occurrence of a\n * specified value in an array, or `-1` if it's not present.\n *\n * @param array - The array to search through.\n * @param searchElement \u2014 The value to locate in the array.\n * @param max \u2014 The array index at which to begin searching backward.\n *\n * @returns the index of the last occurrence, or `-1` if it's not present.\n */\nexport function lastIndexOf(\n array: ArrayLike,\n searchElement: T,\n max: number,\n): number {\n while (--max >= 0) {\n if (array[max] === searchElement) {\n return max;\n }\n }\n return -1;\n}\n", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown: number[] = [];\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.push(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return grown;\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"node:worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { readSync } from \"fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { lastIndexOf } from \"./utils/stream\";\nimport { Config } from \"./constants/config\";\n\nexport function run({\n id,\n // I/O\n fd,\n fileSize,\n pageSize,\n chunkSize,\n // Shared memory\n counts,\n maxes,\n mins,\n page,\n sums,\n}: ProcessRequest): ProcessResponse {\n const newStation = (index: number, temp: number): void => {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n };\n\n const updateStation = (index: number, temp: number): void => {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n };\n\n // Initialize constants\n const chunk = Buffer.allocUnsafe(chunkSize + Config.SYS_PAGE_SIZE);\n let stations = id * BRC.MAX_STATIONS;\n let trie = createTrie(id);\n\n // For each page\n // eslint-disable-next-line no-constant-condition\n while (true) {\n // Get page start\n let start = pageSize * Atomics.add(page, 0, 1);\n if (start >= fileSize) {\n break;\n }\n\n // Align start with entry\n let bufI = start > 0 ? Config.SYS_PAGE_SIZE : 0;\n readSync(fd, chunk, 0, bufI, start - bufI);\n let minI = lastIndexOf(chunk, CharCode.NEWLINE, bufI);\n\n // For each chunk\n const end = Math.min(fileSize, start + pageSize);\n for (++minI; start < end; start += chunkSize) {\n // Move incomplete entry to start of buffer\n let maxI = Config.SYS_PAGE_SIZE - bufI + minI;\n chunk.copyWithin(maxI, minI, bufI);\n bufI = Config.SYS_PAGE_SIZE;\n minI = maxI;\n\n // Read the chunk into memory\n maxI = Math.min(chunkSize, end - start);\n maxI = readSync(fd, chunk, bufI, maxI, start);\n\n // For each byte\n for (maxI += bufI; bufI < maxI; ++bufI) {\n // If not newline\n if (chunk[bufI] !== CharCode.NEWLINE) {\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 5;\n if (chunk[semI] !== CharCode.SEMICOLON) {\n semI += 1 | (1 + ~(chunk[semI - 1] === CharCode.SEMICOLON));\n }\n\n // Add the station's name to the trie and get leaf\n let leaf: number;\n [trie, leaf] = add(trie, chunk, minI, semI);\n\n // Update next entry's min\n minI = bufI + 1;\n\n // Get temperature\n const temp = parseDouble(chunk, semI + 1, bufI);\n\n // If the station existed\n leaf += TrieNodeProto.VALUE_IDX;\n if (trie[leaf] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf], temp);\n } else {\n // Add the new station's value\n trie[leaf] = ++stations;\n newStation(stations, temp);\n }\n }\n }\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n const ids = mergeLeft(tries, a, b, (ai: number, bi: number): void => {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = mins[ai] <= mins[bi] ? mins[ai] : mins[bi];\n maxes[ai] = maxes[ai] >= maxes[bi] ? maxes[ai] : maxes[bi];\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n });\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], + "mappings": "AAAA,OAAS,wBAAAA,MAA4B,UACrC,OAAS,iBAAAC,MAAqB,WAC9B,OAAS,gBAAAC,GAAc,cAAAC,MAAkB,sBCFzC,OACE,aAAAC,EACA,qBAAAC,EACA,aAAAC,EACA,YAAAC,MAEK,UACP,OAAS,UAAAC,MAAc,eCIhB,SAASC,EAAMC,EAAeC,EAAaC,EAAqB,CACrE,OAAOF,EAAQC,EAAOD,GAASE,EAAMF,EAAQE,EAAOD,CACtD,CASO,SAASE,EAAaC,EAAsB,CAEjD,OAAAA,EAAO,KAAK,KAAKA,EAAO,CAAuB,EAE/CA,GAAQ,MAAwBA,EAAO,MAEhCL,EAAMK,gBAAkD,CACjE,CAUO,SAASC,EAAYC,EAAkBC,EAAyB,CAErE,OAAAD,EAAW,KAAK,KAAKA,EAAWC,CAAO,EAEvCD,GAAY,MAAwBA,EAAW,MAExCP,EAAMO,gBAAoD,CACnE,CAYO,SAASE,EACdC,EACAC,EACAR,EACQ,CACR,KAAO,EAAEA,GAAO,GACd,GAAIO,EAAMP,CAAG,IAAMQ,EACjB,OAAOR,EAGX,MAAO,EACT,CC1DO,SAASS,EACdC,EACAC,EACAC,EACAC,EACsB,CACtB,IAAIC,IACJ,KAAOF,EAAMC,GAAK,CAChBC,GACE,EACA,GAAwBH,EAAIC,GAAK,EAAI,IACvC,IAAIG,EAAQL,EAAKI,EAAQ,CAAwB,EAC7CC,IAAU,IAEZA,EAAQL,GAAuB,EAC3BK,EAAQ,IAAoBL,EAAK,SACnCA,EAAOM,EAAKN,EAAMK,EAAQ,GAAiB,GAE7CL,GAAuB,GAAK,IAE5BA,EAAKI,EAAQ,CAAwB,EAAIC,EAEzCL,EAAKK,EAAQ,CAAoB,EAAIL,GAAqB,GAE5DI,EAAQC,CACV,CAEA,MAAO,CAACL,EAAMI,CAAK,CACrB,CA8BO,SAASG,EAAWC,EAAK,EAAGC,SAAsC,CACvEA,EAAO,KAAK,QAAmBA,CAAI,EACnC,IAAMC,EAAO,IAAI,WAAW,IAAI,kBAAkBD,GAAQ,CAAC,CAAC,EAC5D,OAAAC,GAAuB,EAAI,IAC3BA,GAAqB,EAAIF,EAClBE,CACT,CAEO,SAASC,EAAKD,EAAkBE,EAAU,EAAe,CAC9D,IAAMC,EAASH,GAAuB,EACtCE,EAAU,KAAK,IAAIA,EAAS,KAAK,KAAKC,EAAS,iBAAkB,CAAC,EAClE,IAAMC,EAAO,IAAI,WAAW,IAAI,kBAAkBF,GAAW,CAAC,CAAC,EAC/D,QAASG,EAAI,EAAGA,EAAIF,EAAQ,EAAEE,EAC5BD,EAAKC,CAAC,EAAIL,EAAKK,CAAC,EAElB,OAAOD,CACT,CAEO,SAASE,EACdC,EACAC,EACAC,EACAC,EACU,CACV,IAAMC,EAAkB,CAAC,EACnBC,EAA4C,CAChD,CAACJ,IAAwBC,GAAsB,CACjD,EAEA,EAAG,CACD,IAAMI,EAAID,EAAM,OAChB,QAASE,EAAI,EAAGA,EAAID,EAAG,EAAEC,EAAG,CAE1B,GAAI,CAACN,EAAIO,EAAIN,EAAIO,CAAE,EAAIJ,EAAME,CAAC,EAGxBG,EAAMV,EAAME,CAAE,EAAEO,EAAK,CAAuB,EAClD,GAAIC,IAAQ,EAAW,CAErB,IAAMC,EAAMX,EAAMC,CAAE,EAAEO,EAAK,CAAuB,EAC9CG,IAAQ,EACVR,EAAQQ,EAAKD,CAAG,EAEhBV,EAAMC,CAAE,EAAEO,EAAK,CAAuB,EAAIE,CAE9C,CAGAF,GAAM,EACNC,GAAM,EAGN,IAAMG,EAAKH,EAAK,IAChB,KAAOA,EAAKG,GAAI,CAEd,IAAIC,EAAKb,EAAME,CAAE,EAAEO,EAAK,CAAwB,EAChD,GAAII,IAAO,EAAW,CAEpB,IAAMC,EAAKd,EAAME,CAAE,EAAEW,EAAK,CAAoB,EAC1CX,IAAOY,IACTD,EAAKb,EAAME,CAAE,EAAEW,EAAK,CAAyB,GAI/C,IAAIE,EAAKf,EAAMC,CAAE,EAAEO,EAAK,CAAwB,EAChD,GAAIO,IAAO,EAETA,EAAKf,EAAMC,CAAE,GAAoB,EAC7Bc,EAAK,EAAwBf,EAAMC,CAAE,EAAE,SACzCD,EAAMC,CAAE,EAAIP,EAAKM,EAAMC,CAAE,EAAGc,EAAK,CAAqB,EACtDX,EAAM,KAAKH,CAAE,GAEfD,EAAMC,CAAE,GAAoB,GAAK,EAEjCD,EAAMC,CAAE,EAAEO,EAAK,CAAwB,EAAIO,EAE3Cf,EAAMC,CAAE,EAAEc,EAAK,CAAwB,EAAID,EAC3Cd,EAAMC,CAAE,EAAEc,EAAK,CAAyB,EAAIF,MACvC,CAEL,IAAMG,EAAKhB,EAAMC,CAAE,EAAEc,EAAK,CAAoB,EAC1Cd,IAAOe,IACTD,EAAKf,EAAMC,CAAE,EAAEc,EAAK,CAAyB,GAG/CV,EAAM,KAAK,CAACW,EAAID,EAAID,EAAID,CAAE,CAAC,CAC7B,CACF,CAGAL,GAAM,EACNC,GAAM,CACR,CACF,CACAJ,EAAM,OAAO,EAAGC,CAAC,CACnB,OAASD,EAAM,OAAS,GACxB,OAAOD,CACT,CAEO,SAASa,EACdjB,EACAkB,EACAC,EACAC,EACAC,EAAY,GACZC,EAMM,CACN,IAAMC,EAAQ,IAAI,MAAgCL,EAAI,OAAS,CAAC,EAChEK,EAAM,CAAC,EAAI,CAACJ,EAAW,EAAiD,CAAC,EAEzE,IAAIK,EAAM,EACNC,EAAO,GACX,EAAG,CAED,GAAI,CAACC,EAAOC,EAAUC,CAAQ,EAAIL,EAAMC,CAAG,EAG3C,GAAII,GAAY,IAA4B,CAC1C,EAAEJ,EACF,QACF,CAGAD,EAAMC,CAAG,EAAE,CAAC,GAAK,EACjB,EAAED,EAAMC,CAAG,EAAE,CAAC,EAGd,IAAIK,EAAS7B,EAAM0B,CAAK,EAAEC,EAAW,CAAwB,EAC7D,GAAIE,IAAW,EACb,SAIF,IAAMC,EAAa9B,EAAM0B,CAAK,EAAEG,EAAS,CAAoB,EACzDH,IAAUI,IACZD,EAAS7B,EAAM0B,CAAK,EAAEG,EAAS,CAAyB,EACxDH,EAAQI,GAIVZ,EAAIM,CAAG,EAAII,EAAW,GACtBL,EAAM,EAAEC,CAAG,EAAI,CAACE,EAAOG,EAAS,EAA4B,CAAC,EAG7D,IAAME,EAAa/B,EAAM0B,CAAK,EAAEG,EAAS,CAAuB,EAC5DE,IAAe,IAEbN,GACFL,EAAO,MAAMC,CAAS,EAExBI,EAAO,GACPH,EAAWF,EAAQF,EAAKM,EAAKO,CAAU,EAE3C,OAASP,GAAO,EAClB,CCpOA,OAAS,UAAAQ,MAAc,sBAShB,SAASC,EAAaC,EAA4B,CACvD,IAAMC,EAAS,IAAIH,EAAOE,CAAU,EACpC,OAAAC,EAAO,GAAG,QAAUC,GAAQ,CAC1B,MAAMA,CACR,CAAC,EACDD,EAAO,GAAG,eAAiBC,GAAQ,CACjC,MAAMA,CACR,CAAC,EACDD,EAAO,GAAG,OAASE,GAAS,CAC1B,GAAIA,EAAO,GAAKA,EAAO,EACrB,MAAM,IAAI,MAAM,UAAUF,EAAO,QAAQ,qBAAqBE,CAAI,EAAE,CAExE,CAAC,EACMF,CACT,CAUO,SAASG,EAAeH,EAAgBI,EAAwB,CACrE,OAAO,IAAI,QAAcC,GAAY,CACnCL,EAAO,KAAK,UAAWK,CAAO,EAC9BL,EAAO,YAAYI,CAAG,CACxB,CAAC,CACH,CHjBA,eAAsBE,EACpBC,EACAC,EACAC,EACAC,EAAU,GACK,CAEfD,EAAaE,EAAMF,OAAkD,EAGrE,IAAMG,EAAKC,EAASN,EAAU,GAAG,EAI3BO,EADSC,EAAUH,CAAE,EACH,KAClBI,EAAWC,EAAYH,EAAUL,CAAU,EAC3CS,EAAYC,EAAaH,CAAQ,EAGjCI,EAAS,IAAI,kBAChB,IAAmBX,EAAa,GAAM,CACzC,EACMY,EAAO,IAAI,YAAYD,EAAQ,EAAG,CAAC,EACnCE,EAAO,IAAI,WAAWF,CAAM,EAC5BG,EAAQ,IAAI,WAAWH,EAAQ,CAAC,EAChCI,EAAS,IAAI,YAAYJ,EAAQ,CAAC,EAClCK,EAAO,IAAI,aAAaL,EAAQ,CAAC,EACjCM,EAAQ,IAAI,MAAkBjB,CAAU,EAGxCkB,EAAqB,CAAC,EACtBC,EAAQ,IAAI,MAAwBnB,CAAU,EACpD,QAASoB,EAAI,EAAGA,EAAIpB,EAAY,EAAEoB,EAAG,CAEnC,IAAMC,EAASC,EAAavB,CAAU,EAEtCoB,EAAMC,CAAC,EAAIG,EAAsCF,EAAQ,CACvD,OACA,GAAID,EAEJ,GAAAjB,EACA,SAAAE,EACA,SAAAE,EACA,UAAAE,EAEA,OAAAM,EACA,MAAAD,EACA,KAAAD,EACA,KAAAD,EACA,KAAAI,CACF,CAAC,EAAE,KAAK,MAAOQ,GAAQ,CAErB,IAAMC,EAAID,EAAI,GAGd,IAFAP,EAAMQ,CAAC,EAAID,EAAI,KAERN,EAAS,OAAS,GAAG,CAC1B,IAAMM,EAAM,MAAMD,EAAkCF,EAAQ,CAC1D,OACA,EAAAI,EACA,EAAGP,EAAS,IAAI,EAChB,OAAAH,EACA,MAAAD,EACA,KAAAD,EACA,KAAAG,EACA,MAAAC,CACF,CAAC,EAED,QAAWS,KAAMF,EAAI,IACnBP,EAAMS,CAAE,EAAIF,EAAI,MAAME,CAAE,CAE5B,CACA,OAAAR,EAAS,KAAKO,CAAC,EAERJ,EAAO,UAAU,CAC1B,CAAC,CACH,CAGA,MAAM,QAAQ,IAAIF,CAAK,EAGvBQ,EAAUxB,CAAE,EAGZ,IAAMyB,EAAMC,EAAkB5B,EAAS,CACrC,GAAIA,EAAQ,OAAS,EAAI6B,EAAO,GAAK,OACrC,MAAO,IACP,qBACF,CAAC,EACKC,EAAS,OAAO,eAAoC,EAC1DH,EAAI,MAAM,GAAG,EACbI,EAAMf,EAAOc,EAAQb,EAAS,CAAC,EAAGU,EAAK,KAAMK,CAAY,EACzDL,EAAI,IAAI;AAAA,CAAK,EAEb,SAASK,EACPC,EACAC,EACAC,EACAC,EACM,CACN,IAAMC,EAAM,KAAK,MAAMtB,EAAKqB,GAAM,CAAC,EAAItB,EAAOsB,GAAM,CAAC,CAAC,EACtDH,EAAO,MAAMC,EAAK,SAAS,OAAQ,EAAGC,CAAO,CAAC,EAC9CF,EAAO,MAAM,GAAG,EAChBA,EAAO,OAAOrB,EAAKwB,GAAM,CAAC,EAAI,IAAI,QAAQ,CAAC,CAAC,EAC5CH,EAAO,MAAM,GAAG,EAChBA,EAAO,OAAOI,EAAM,IAAI,QAAQ,CAAC,CAAC,EAClCJ,EAAO,MAAM,GAAG,EAChBA,EAAO,OAAOpB,EAAMuB,GAAM,CAAC,EAAI,IAAI,QAAQ,CAAC,CAAC,CAC/C,CACF,CIlIA,OAAS,YAAAE,MAAgB,KCElB,IAAMC,EAAe,GAAK,GACpBC,EAAgB,IAAM,GAO5B,SAASC,EAAYC,EAAWC,EAAaC,EAAqB,CACvE,OAAIF,EAAEC,CAAG,IAAM,IACb,EAAEA,EACKA,EAAM,EAAIC,EACbL,EAAe,GAAKG,EAAEC,CAAG,EAAID,EAAEC,EAAM,CAAC,EACtCH,EAAgB,IAAME,EAAEC,CAAG,EAAI,GAAKD,EAAEC,EAAM,CAAC,EAAID,EAAEC,EAAM,CAAC,GAEzDA,EAAM,EAAIC,EACb,GAAKF,EAAEC,CAAG,EAAID,EAAEC,EAAM,CAAC,EAAIJ,EAC3B,IAAMG,EAAEC,CAAG,EAAI,GAAKD,EAAEC,EAAM,CAAC,EAAID,EAAEC,EAAM,CAAC,EAAIH,CACpD,CDNO,SAASK,EAAI,CAClB,GAAAC,EAEA,GAAAC,EACA,SAAAC,EACA,SAAAC,EACA,UAAAC,EAEA,OAAAC,EACA,MAAAC,EACA,KAAAC,EACA,KAAAC,EACA,KAAAC,CACF,EAAoC,CAClC,IAAMC,EAAa,CAACC,EAAeC,IAAuB,CACxDL,EAAKI,GAAS,CAAC,EAAIC,EACnBN,EAAMK,GAAS,CAAC,EAAIC,EACpBP,EAAOM,GAAS,CAAC,EAAI,EACrBF,EAAKE,GAAS,CAAC,EAAIC,CACrB,EAEMC,EAAgB,CAACF,EAAeC,IAAuB,CAC3DD,IAAU,EACVJ,EAAKI,CAAK,EAAIJ,EAAKI,CAAK,GAAKC,EAAOL,EAAKI,CAAK,EAAIC,EAClDN,EAAMK,CAAK,EAAIL,EAAMK,CAAK,GAAKC,EAAON,EAAMK,CAAK,EAAIC,EACrD,EAAEP,EAAOM,GAAS,CAAC,EACnBF,EAAKE,GAAS,CAAC,GAAKC,CACtB,EAGME,EAAQ,OAAO,YAAYV,EAAY,KAAoB,EAC7DW,EAAWf,EAAK,IAChBgB,EAAOC,EAAWjB,CAAE,EAIxB,OAAa,CAEX,IAAIkB,EAAQf,EAAW,QAAQ,IAAIK,EAAM,EAAG,CAAC,EAC7C,GAAIU,GAAShB,EACX,MAIF,IAAIiB,EAAOD,EAAQ,QAA2B,EAC9CE,EAASnB,EAAIa,EAAO,EAAGK,EAAMD,EAAQC,CAAI,EACzC,IAAIE,EAAOC,EAAYR,KAAyBK,CAAI,EAG9CI,EAAM,KAAK,IAAIrB,EAAUgB,EAAQf,CAAQ,EAC/C,IAAK,EAAEkB,EAAMH,EAAQK,EAAKL,GAASd,EAAW,CAE5C,IAAIoB,EAAO,MAAuBL,EAAOE,EAUzC,IATAP,EAAM,WAAWU,EAAMH,EAAMF,CAAI,EACjCA,EAAO,MACPE,EAAOG,EAGPA,EAAO,KAAK,IAAIpB,EAAWmB,EAAML,CAAK,EACtCM,EAAOJ,EAASnB,EAAIa,EAAOK,EAAMK,EAAMN,CAAK,EAGvCM,GAAQL,EAAMA,EAAOK,EAAM,EAAEL,EAAM,CAEtC,GAAIL,EAAMK,CAAI,IAAM,GAClB,SAIF,IAAIM,EAAON,EAAO,EACdL,EAAMW,CAAI,IAAM,KAClBA,GAAQ,EAAK,EAAI,EAAEX,EAAMW,EAAO,CAAC,IAAM,KAIzC,IAAIC,EACJ,CAACV,EAAMU,CAAI,EAAIC,EAAIX,EAAMF,EAAOO,EAAMI,CAAI,EAG1CJ,EAAOF,EAAO,EAGd,IAAMP,EAAOgB,EAAYd,EAAOW,EAAO,EAAGN,CAAI,EAG9CO,GAAQ,EACJV,EAAKU,CAAI,IAAM,EAEjBb,EAAcG,EAAKU,CAAI,EAAGd,CAAI,GAG9BI,EAAKU,CAAI,EAAI,EAAEX,EACfL,EAAWK,EAAUH,CAAI,EAE7B,CACF,CACF,CAEA,MAAO,CAAE,GAAAZ,EAAI,KAAAgB,CAAK,CACpB,CAEO,SAASa,EAAM,CACpB,EAAAC,EACA,EAAAC,EACA,MAAAC,EACA,OAAA3B,EACA,MAAAC,EACA,KAAAC,EACA,KAAAE,CACF,EAAgC,CAS9B,MAAO,CAAE,IARGwB,EAAUD,EAAOF,EAAGC,EAAG,CAACG,EAAYC,IAAqB,CACnED,IAAO,EACPC,IAAO,EACP5B,EAAK2B,CAAE,EAAI3B,EAAK2B,CAAE,GAAK3B,EAAK4B,CAAE,EAAI5B,EAAK2B,CAAE,EAAI3B,EAAK4B,CAAE,EACpD7B,EAAM4B,CAAE,EAAI5B,EAAM4B,CAAE,GAAK5B,EAAM6B,CAAE,EAAI7B,EAAM4B,CAAE,EAAI5B,EAAM6B,CAAE,EACzD9B,EAAO6B,GAAM,CAAC,GAAK7B,EAAO8B,GAAM,CAAC,EACjC1B,EAAKyB,GAAM,CAAC,GAAKzB,EAAK0B,GAAM,CAAC,CAC/B,CAAC,EACa,MAAAH,CAAM,CACtB,CL1HA,GAAII,GAAc,CAChB,IAAMC,EAAaC,EAAc,YAAY,GAAG,EAChDC,EAAQ,QAAQ,KAAK,CAAC,EAAGF,EAAYG,EAAqB,CAAC,CAC7D,MACEC,EAAY,YAAY,UAAYC,GAAiB,CACnD,GAAIA,EAAI,OAAS,EACfD,EAAY,YAAYF,EAAUG,CAAqB,CAAC,UAC/CA,EAAI,OAAS,EACtBD,EAAY,YAAYE,EAAMD,CAAmB,CAAC,MAElD,OAAM,IAAI,MAAM,sBAAsB,CAE1C,CAAC", "names": ["availableParallelism", "fileURLToPath", "isMainThread", "parentPort", "closeSync", "createWriteStream", "fstatSync", "openSync", "stdout", "clamp", "value", "min", "max", "getChunkSize", "size", "getPageSize", "fileSize", "workers", "lastIndexOf", "array", "searchElement", "add", "trie", "key", "min", "max", "index", "child", "grow", "createTrie", "id", "size", "trie", "grow", "minSize", "length", "next", "i", "mergeLeft", "tries", "at", "bt", "mergeFn", "grown", "queue", "Q", "q", "ai", "bi", "bvi", "avi", "bn", "ri", "rt", "li", "lt", "print", "key", "trieIndex", "stream", "separator", "callbackFn", "stack", "top", "tail", "trieI", "childPtr", "numChild", "childI", "childTrieI", "valueIndex", "Worker", "createWorker", "workerPath", "worker", "err", "code", "exec", "req", "resolve", "run", "filePath", "workerPath", "maxWorkers", "outPath", "clamp", "fd", "openSync", "fileSize", "fstatSync", "pageSize", "getPageSize", "chunkSize", "getChunkSize", "valBuf", "page", "mins", "maxes", "counts", "sums", "tries", "unmerged", "tasks", "i", "worker", "createWorker", "exec", "res", "a", "id", "closeSync", "out", "createWriteStream", "stdout", "buffer", "print", "printStation", "stream", "name", "nameLen", "vi", "avg", "readSync", "CHAR_ZERO_11", "CHAR_ZERO_111", "parseDouble", "b", "min", "max", "run", "id", "fd", "fileSize", "pageSize", "chunkSize", "counts", "maxes", "mins", "page", "sums", "newStation", "index", "temp", "updateStation", "chunk", "stations", "trie", "createTrie", "start", "bufI", "readSync", "minI", "lastIndexOf", "end", "maxI", "semI", "leaf", "add", "parseDouble", "merge", "a", "b", "tries", "mergeLeft", "ai", "bi", "isMainThread", "workerPath", "fileURLToPath", "run", "availableParallelism", "parentPort", "msg", "merge"] } From 92d1ab27ce430de34ec46ba6d67782c6fcff22d2 Mon Sep 17 00:00:00 2001 From: Michael Rojas Date: Fri, 11 Jul 2025 01:01:53 -0400 Subject: [PATCH 69/69] Update packages and README --- calculate_average_havelessbemore.sh | 2 +- src/main/nodejs/havelessbemore/.gitignore | 143 + .../nodejs/havelessbemore/.prettierignore | 2 +- src/main/nodejs/havelessbemore/README.md | 23 +- .../nodejs/havelessbemore/benchmarks/bench.ts | 65 - src/main/nodejs/havelessbemore/dist/index.mjs | 3 - .../nodejs/havelessbemore/dist/index.mjs.map | 7 - .../nodejs/havelessbemore/esbuild.config.js | 19 - .../nodejs/havelessbemore/eslint.config.js | 12 - .../nodejs/havelessbemore/eslint.config.mjs | 48 + .../nodejs/havelessbemore/package-lock.json | 3117 +++++++++++------ src/main/nodejs/havelessbemore/package.json | 58 +- .../havelessbemore/src/benchmarks/index.ts | 72 + src/main/nodejs/havelessbemore/src/index.ts | 4 +- src/main/nodejs/havelessbemore/src/main.ts | 34 +- .../nodejs/havelessbemore/src/types/index.ts | 6 + .../havelessbemore/src/types/response.ts | 2 +- src/main/nodejs/havelessbemore/src/worker.ts | 3 +- src/main/nodejs/havelessbemore/tsconfig.json | 66 +- src/main/nodejs/havelessbemore/tsup.config.ts | 34 + 20 files changed, 2378 insertions(+), 1342 deletions(-) create mode 100644 src/main/nodejs/havelessbemore/.gitignore delete mode 100644 src/main/nodejs/havelessbemore/benchmarks/bench.ts delete mode 100644 src/main/nodejs/havelessbemore/dist/index.mjs delete mode 100644 src/main/nodejs/havelessbemore/dist/index.mjs.map delete mode 100644 src/main/nodejs/havelessbemore/esbuild.config.js delete mode 100644 src/main/nodejs/havelessbemore/eslint.config.js create mode 100644 src/main/nodejs/havelessbemore/eslint.config.mjs create mode 100644 src/main/nodejs/havelessbemore/src/benchmarks/index.ts create mode 100644 src/main/nodejs/havelessbemore/src/types/index.ts create mode 100644 src/main/nodejs/havelessbemore/tsup.config.ts diff --git a/calculate_average_havelessbemore.sh b/calculate_average_havelessbemore.sh index 2795552..086f4c5 100755 --- a/calculate_average_havelessbemore.sh +++ b/calculate_average_havelessbemore.sh @@ -15,4 +15,4 @@ # limitations under the License. # -time node --enable-source-maps src/main/nodejs/havelessbemore/dist/index.mjs measurements.txt +time node --enable-source-maps src/main/nodejs/havelessbemore/dist/cjs/index.cjs measurements.txt diff --git a/src/main/nodejs/havelessbemore/.gitignore b/src/main/nodejs/havelessbemore/.gitignore new file mode 100644 index 0000000..88deff9 --- /dev/null +++ b/src/main/nodejs/havelessbemore/.gitignore @@ -0,0 +1,143 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +### Template: https://github.com/github/gitignore/blob/main/Node.gitignore ### + +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.* +!.env.example + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# Sveltekit cache directory +.svelte-kit/ + +# vitepress build output +**/.vitepress/dist + +# vitepress cache directory +**/.vitepress/cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# Firebase cache directory +.firebase/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v3 +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/sdks +!.yarn/versions + +# Vite logs files +vite.config.js.timestamp-* +vite.config.ts.timestamp-* diff --git a/src/main/nodejs/havelessbemore/.prettierignore b/src/main/nodejs/havelessbemore/.prettierignore index 381e69d..f25bad1 100644 --- a/src/main/nodejs/havelessbemore/.prettierignore +++ b/src/main/nodejs/havelessbemore/.prettierignore @@ -1,3 +1,3 @@ .husky dist -docs \ No newline at end of file +docsa \ No newline at end of file diff --git a/src/main/nodejs/havelessbemore/README.md b/src/main/nodejs/havelessbemore/README.md index d33e9d7..17f99b3 100644 --- a/src/main/nodejs/havelessbemore/README.md +++ b/src/main/nodejs/havelessbemore/README.md @@ -14,23 +14,22 @@ ### Results -- Min: 11.1s -- Avg: 11.6s -- Max: 12.0s -- Samples: 10 runs, 5s apart +- Min: 4.477s +- Avg: 4.528s +- Max: 4.578s +- Samples: 5 runs, 5s apart #### Specs: - Machine: - - - Model: MacBook Air - - Chip: Apple M2 - - Cores: 8 (4 performance + 4 efficiency) - - Memory: 8 GB - - OS: MacOS Sonoma + - Model: MacBook Pro + - Chip: Apple M4 Max + - Cores: 14 (10 performance and 4 efficiency) + - Memory: 36 GB + - OS: MacOS Sequoia - Other: - - NodeJS: v20.14.0 + - NodeJS: v22.17.0 - Input file: ~13.8 GB ## Build @@ -55,4 +54,4 @@ npm install npm run build ``` -Output is built in the `dist/` directory as ECMAScript (`.mjs`) modules. +Output is built in the `dist/` directory. diff --git a/src/main/nodejs/havelessbemore/benchmarks/bench.ts b/src/main/nodejs/havelessbemore/benchmarks/bench.ts deleted file mode 100644 index 86437af..0000000 --- a/src/main/nodejs/havelessbemore/benchmarks/bench.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { mkdtemp, rm } from "fs/promises"; -import { join, resolve } from "path"; -import { stdout } from "process"; -import { availableParallelism, tmpdir } from "os"; -import { fileURLToPath } from "url"; - -import { Bench, Task } from "tinybench"; - -import { run } from "../src/main"; - -// INPUT -const filePath = process.argv[2]; -const maxWorkers = availableParallelism(); -const workerPath = resolve( - fileURLToPath(import.meta.url), - "../../dist/index.mjs", -); - -// OUTPUT -const dir = await mkdtemp(join(tmpdir(), "1brc-")); - -// BENCHMARK -let i = 0; -let t0 = 0; -const bench = new Bench({ iterations: 5 }); -bench.add( - `1BRC`, - async () => { - const outPath = join(dir, `out_${i}.txt`); - return run(filePath, workerPath, maxWorkers, outPath); - }, - { - beforeAll: () => { - t0 = performance.now(); - }, - beforeEach: function (): void { - const elapsed = toSeconds(performance.now() - t0); - console.log(`${this.name} (${elapsed}s): Running iteration ${++i}...`); - }, - }, -); - -await bench.run(); - -// CLEANUP -await rm(dir, { recursive: true, force: true }); - -// REPORTING -function toRecord(task: Task): Record { - const out: Record = {}; - out.Name = task.name; - out["Min (s)"] = toSeconds(task.result?.min); - out["Max (s)"] = toSeconds(task.result?.max); - out["Avg (s)"] = toSeconds(task.result?.mean); - out.Samples = +(task.result?.samples ?? []).length; - return out; -} - -function toSeconds(ms: number | undefined): number { - return Math.floor(ms ?? 0) / 1000; -} - -console.table(bench.tasks.map((task) => toRecord(task))); -const time = bench.tasks.reduce((sum, t) => sum + t.result!.totalTime, 0); -stdout.write(`Total time: ${toSeconds(time)}s\n`); diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs b/src/main/nodejs/havelessbemore/dist/index.mjs deleted file mode 100644 index 217a22e..0000000 --- a/src/main/nodejs/havelessbemore/dist/index.mjs +++ /dev/null @@ -1,3 +0,0 @@ -import{availableParallelism as J}from"node:os";import{fileURLToPath as z}from"node:url";import{isMainThread as ee,parentPort as w}from"node:worker_threads";import{closeSync as K,createWriteStream as V,fstatSync as Q,openSync as $}from"node:fs";import{stdout as j}from"node:process";function h(e,r,t){return e>r?e<=t?e:t:r}function N(e){return e=Math.ceil(e*1),e+=16384-e%16384,h(e,16384,16777216)}function P(e,r){return e=Math.ceil(e/r),e+=16384-e%16384,h(e,16384,16777216)}function T(e,r,t){for(;--t>=0;)if(e[t]===r)return t;return-1}function O(e,r,t,a){let f=1;for(;te.length&&(e=U(e,I+218)),e[0]+=218,e[f+0]=I,e[I+0]=e[1]),f=I}return[e,f]}function C(e=0,r=655360){r=Math.max(219,r);let t=new Int32Array(new SharedArrayBuffer(r<<2));return t[0]=219,t[1]=e,t}function U(e,r=0){let t=e[0];r=Math.max(r,Math.ceil(t*1.618033988749895));let a=new Int32Array(new SharedArrayBuffer(r<<2));for(let f=0;fe[n].length&&(e[n]=U(e[n],o+2),f.push(n)),e[n][0]+=2,e[n][s+0]=o,e[n][o+0]=u,e[n][o+1]=c;else{let l=e[n][o+0];n!==l&&(o=e[n][o+1]),I.push([l,o,u,c])}}s+=1,E+=1}}I.splice(0,m)}while(I.length>0);return f}function Z(e,r,t,a,f="",I){let m=new Array(r.length+1);m[0]=[t,3,0];let i=0,n=!1;do{let[s,R,E]=m[i];if(E>=216){--i;continue}m[i][1]+=1,++m[i][2];let p=e[s][R+0];if(p===0)continue;let D=e[s][p+0];s!==D&&(p=e[s][p+1],s=D),r[i]=E+32,m[++i]=[s,p+2,0];let c=e[s][p+1];c!==0&&(n&&a.write(f),n=!0,I(a,r,i,c))}while(i>=0)}import{Worker as F}from"node:worker_threads";function B(e){let r=new F(e);return r.on("error",t=>{throw t}),r.on("messageerror",t=>{throw t}),r.on("exit",t=>{if(t>1||t<0)throw new Error(`Worker ${r.threadId} exited with code ${t}`)}),r}function b(e,r){return new Promise(t=>{e.once("message",t),e.postMessage(r)})}async function H(e,r,t,a=""){t=h(t,1,256);let f=$(e,"r"),m=Q(f).size,i=P(m,t),n=N(i),s=new SharedArrayBuffer(1e4*t+1<<4),R=new Uint32Array(s,0,1),E=new Int16Array(s),p=new Int16Array(s,2),D=new Uint32Array(s,4),c=new Float64Array(s,8),u=new Array(t),o=[],l=new Array(t);for(let _=0;_{let y=g.id;for(u[y]=g.trie;o.length>0;){let d=await b(S,{type:1,a:y,b:o.pop(),counts:D,maxes:p,mins:E,sums:c,tries:u});for(let L of d.ids)u[L]=d.tries[L]}return o.push(y),S.terminate()})}await Promise.all(l),K(f);let A=V(a,{fd:a.length<1?j.fd:void 0,flags:"a",highWaterMark:1048576}),M=Buffer.allocUnsafe(100);A.write("{"),Z(u,M,o[0],A,", ",X),A.end(`} -`);function X(_,S,g,y){let d=Math.round(c[y<<1]/D[y<<2]);_.write(S.toString("utf8",0,g)),_.write("="),_.write((E[y<<3]/10).toFixed(1)),_.write("/"),_.write((d/10).toFixed(1)),_.write("/"),_.write((p[y<<3]/10).toFixed(1))}}import{readSync as v}from"fs";var k=11*48,W=111*48;function G(e,r,t){return e[r]===45?(++r,r+4>t?k-10*e[r]-e[r+2]:W-100*e[r]-10*e[r+1]-e[r+3]):r+4>t?10*e[r]+e[r+2]-k:100*e[r]+10*e[r+1]+e[r+3]-W}function x({id:e,fd:r,fileSize:t,pageSize:a,chunkSize:f,counts:I,maxes:m,mins:i,page:n,sums:s}){let R=(u,o)=>{i[u<<3]=o,m[u<<3]=o,I[u<<2]=1,s[u<<1]=o},E=(u,o)=>{u<<=3,i[u]=i[u]<=o?i[u]:o,m[u]=m[u]>=o?m[u]:o,++I[u>>1],s[u>>2]+=o},p=Buffer.allocUnsafe(f+16384),D=e*1e4,c=C(e);for(;;){let u=a*Atomics.add(n,0,1);if(u>=t)break;let o=u>0?16384:0;v(r,p,0,o,u-o);let l=T(p,10,o),A=Math.min(t,u+a);for(++l;u{n<<=3,s<<=3,I[n]=I[n]<=I[s]?I[n]:I[s],f[n]=f[n]>=f[s]?f[n]:f[s],a[n>>1]+=a[s>>1],m[n>>2]+=m[s>>2]}),tries:t}}if(ee){let e=z(import.meta.url);H(process.argv[2],e,J())}else w.addListener("message",e=>{if(e.type===0)w.postMessage(x(e));else if(e.type===1)w.postMessage(Y(e));else throw new Error("Unknown message type")}); -//# sourceMappingURL=index.mjs.map diff --git a/src/main/nodejs/havelessbemore/dist/index.mjs.map b/src/main/nodejs/havelessbemore/dist/index.mjs.map deleted file mode 100644 index 56bcadb..0000000 --- a/src/main/nodejs/havelessbemore/dist/index.mjs.map +++ /dev/null @@ -1,7 +0,0 @@ -{ - "version": 3, - "sources": ["../src/index.ts", "../src/main.ts", "../src/utils/stream.ts", "../src/utils/utf8Trie.ts", "../src/utils/worker.ts", "../src/worker.ts", "../src/utils/parse.ts"], - "sourcesContent": ["import { availableParallelism } from \"node:os\";\nimport { fileURLToPath } from \"node:url\";\nimport { isMainThread, parentPort } from \"node:worker_threads\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport { RequestType, type Request } from \"./types/request\";\n\nimport { run as runMain } from \"./main\";\nimport { merge, run as runWorker } from \"./worker\";\n\nif (isMainThread) {\n const workerPath = fileURLToPath(import.meta.url);\n runMain(process.argv[2], workerPath, availableParallelism());\n} else {\n parentPort!.addListener(\"message\", (msg: Request) => {\n if (msg.type === RequestType.PROCESS) {\n parentPort!.postMessage(runWorker(msg as ProcessRequest));\n } else if (msg.type === RequestType.MERGE) {\n parentPort!.postMessage(merge(msg as MergeRequest));\n } else {\n throw new Error(\"Unknown message type\");\n }\n });\n}\n", "import {\n closeSync,\n createWriteStream,\n fstatSync,\n openSync,\n WriteStream,\n} from \"node:fs\";\nimport { stdout } from \"node:process\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { Config } from \"./constants/config\";\nimport { RequestType } from \"./types/request\";\nimport { clamp, getChunkSize, getPageSize } from \"./utils/stream\";\nimport { print } from \"./utils/utf8Trie\";\nimport { createWorker, exec } from \"./utils/worker\";\n\nexport async function run(\n filePath: string,\n workerPath: string,\n maxWorkers: number,\n outPath = \"\",\n): Promise {\n // Sanitize number of workers\n maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX);\n\n // Open the given file\n const fd = openSync(filePath, \"r\");\n\n // Get file stats\n const fstats = fstatSync(fd);\n const fileSize = fstats.size;\n const pageSize = getPageSize(fileSize, maxWorkers);\n const chunkSize = getChunkSize(pageSize);\n\n // Initialize data\n const valBuf = new SharedArrayBuffer(\n (BRC.MAX_STATIONS * maxWorkers + 1) << 4,\n );\n const page = new Uint32Array(valBuf, 0, 1);\n const mins = new Int16Array(valBuf);\n const maxes = new Int16Array(valBuf, 2);\n const counts = new Uint32Array(valBuf, 4);\n const sums = new Float64Array(valBuf, 8);\n const tries = new Array(maxWorkers);\n\n // Run\n const unmerged: number[] = [];\n const tasks = new Array>(maxWorkers);\n for (let i = 0; i < maxWorkers; ++i) {\n // Create the worker\n const worker = createWorker(workerPath);\n // Process the chunk\n tasks[i] = exec(worker, {\n type: RequestType.PROCESS,\n id: i,\n // I/O\n fd,\n fileSize,\n pageSize,\n chunkSize,\n // Shared memory\n counts,\n maxes,\n mins,\n page,\n sums,\n }).then(async (res) => {\n // Add result to trie array\n const a = res.id;\n tries[a] = res.trie;\n // Merge with other tries\n while (unmerged.length > 0) {\n const res = await exec(worker, {\n type: RequestType.MERGE,\n a,\n b: unmerged.pop()!,\n counts,\n maxes,\n mins,\n sums,\n tries,\n });\n // Update the trie array\n for (const id of res.ids) {\n tries[id] = res.tries[id];\n }\n }\n unmerged.push(a);\n // Stop worker\n return worker.terminate();\n });\n }\n\n // Wait for completion\n await Promise.all(tasks);\n\n // Close the file\n closeSync(fd);\n\n // Print results\n const out = createWriteStream(outPath, {\n fd: outPath.length < 1 ? stdout.fd : undefined,\n flags: \"a\",\n highWaterMark: Config.HIGH_WATER_MARK_OUT,\n });\n const buffer = Buffer.allocUnsafe(BRC.MAX_STATION_NAME_LEN);\n out.write(\"{\");\n print(tries, buffer, unmerged[0], out, \", \", printStation);\n out.end(\"}\\n\");\n\n function printStation(\n stream: WriteStream,\n name: Buffer,\n nameLen: number,\n vi: number,\n ): void {\n const avg = Math.round(sums[vi << 1] / counts[vi << 2]);\n stream.write(name.toString(\"utf8\", 0, nameLen));\n stream.write(\"=\");\n stream.write((mins[vi << 3] / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((avg / 10).toFixed(1));\n stream.write(\"/\");\n stream.write((maxes[vi << 3] / 10).toFixed(1));\n }\n}\n", "import { Config } from \"../constants/config\";\n\n/**\n * Clamp a value within a given range.\n *\n * @param value - The value to clamp.\n * @param min - The range min (inclusive).\n * @param max - The range max (inclusive).\n *\n * @returns The clamped value.\n */\nexport function clamp(value: number, min: number, max: number): number {\n return value > min ? (value <= max ? value : max) : min;\n}\n\n/**\n * Calculates a chunk size based on a given page size.\n *\n * @param size - The page size.\n *\n * @returns The calculated chunk size.\n */\nexport function getChunkSize(size: number): number {\n // Get size percentage\n size = Math.ceil(size * Config.CHUNK_SIZE_RATIO);\n // Align\n size += Config.SYS_PAGE_SIZE - (size % Config.SYS_PAGE_SIZE);\n // Clamp value\n return clamp(size, Config.CHUNK_SIZE_MIN, Config.CHUNK_SIZE_MAX);\n}\n\n/**\n * Calculates a page size based on a given file size.\n *\n * @param fileSize - The file size.\n * @param workers - The number of workers the file will be split across.\n *\n * @returns The calculated page size.\n */\nexport function getPageSize(fileSize: number, workers: number): number {\n // Divide into workers\n fileSize = Math.ceil(fileSize / workers);\n // Align\n fileSize += Config.SYS_PAGE_SIZE - (fileSize % Config.SYS_PAGE_SIZE);\n // Clamp value\n return clamp(fileSize, Config.PAGE_SIZE_MIN, Config.PAGE_SIZE_MAX);\n}\n\n/**\n * Returns the index of the last occurrence of a\n * specified value in an array, or `-1` if it's not present.\n *\n * @param array - The array to search through.\n * @param searchElement \u2014 The value to locate in the array.\n * @param max \u2014 The array index at which to begin searching backward.\n *\n * @returns the index of the last occurrence, or `-1` if it's not present.\n */\nexport function lastIndexOf(\n array: ArrayLike,\n searchElement: T,\n max: number,\n): number {\n while (--max >= 0) {\n if (array[max] === searchElement) {\n return max;\n }\n }\n return -1;\n}\n", "import { WriteStream } from \"node:fs\";\n\nimport {\n Trie,\n TrieNodeProto,\n TrieProto,\n TriePointerProto,\n TrieRedirectProto,\n UTF8,\n} from \"../constants/utf8\";\n\nexport function add(\n trie: Int32Array,\n key: ArrayLike,\n min: number,\n max: number,\n): [Int32Array, number] {\n let index: number = TrieProto.ROOT_IDX;\n while (min < max) {\n index +=\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = trie[index + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n // Allocate node\n child = trie[TrieProto.SIZE_IDX];\n if (child + TrieNodeProto.MEM > trie.length) {\n trie = grow(trie, child + TrieNodeProto.MEM);\n }\n trie[TrieProto.SIZE_IDX] += TrieNodeProto.MEM;\n // Attach node\n trie[index + TriePointerProto.IDX_IDX] = child;\n // Initialize node\n trie[child + TrieNodeProto.ID_IDX] = trie[TrieProto.ID_IDX];\n }\n index = child;\n }\n\n return [trie, index];\n}\n\nexport function get(\n tries: Int32Array[],\n trie: number,\n key: ArrayLike,\n min: number,\n max: number,\n): number | undefined {\n let node: number = TrieProto.ROOT_IDX;\n while (min < max) {\n const ptr =\n node +\n TrieNodeProto.CHILDREN_IDX +\n TriePointerProto.MEM * (key[min++] - UTF8.BYTE_MIN);\n let child = tries[trie][ptr + TriePointerProto.IDX_IDX];\n if (child === Trie.NULL) {\n return undefined;\n }\n // Resolve redirect, if any\n const childTrie = tries[trie][child + TrieNodeProto.ID_IDX];\n if (childTrie !== trie) {\n child = tries[trie][child + TrieRedirectProto.IDX_IDX];\n trie = childTrie;\n }\n node = child;\n }\n return node;\n}\n\nexport function createTrie(id = 0, size = Trie.DEFAULT_SIZE): Int32Array {\n size = Math.max(TrieProto.MEM, size);\n const trie = new Int32Array(new SharedArrayBuffer(size << 2));\n trie[TrieProto.SIZE_IDX] = TrieProto.MEM;\n trie[TrieProto.ID_IDX] = id;\n return trie;\n}\n\nexport function grow(trie: Int32Array, minSize = 0): Int32Array {\n const length = trie[TrieProto.SIZE_IDX];\n minSize = Math.max(minSize, Math.ceil(length * Trie.GROWTH_FACTOR));\n const next = new Int32Array(new SharedArrayBuffer(minSize << 2));\n for (let i = 0; i < length; ++i) {\n next[i] = trie[i];\n }\n return next;\n}\n\nexport function mergeLeft(\n tries: Int32Array[],\n at: number,\n bt: number,\n mergeFn: (ai: number, bi: number) => void,\n): number[] {\n const grown: number[] = [];\n const queue: [number, number, number, number][] = [\n [at, TrieProto.ROOT_IDX, bt, TrieProto.ROOT_IDX],\n ];\n\n do {\n const Q = queue.length;\n for (let q = 0; q < Q; ++q) {\n // eslint-disable-next-line prefer-const\n let [at, ai, bt, bi] = queue[q];\n\n // If right value is not null\n const bvi = tries[bt][bi + TrieNodeProto.VALUE_IDX];\n if (bvi !== Trie.NULL) {\n // If left value is not null\n const avi = tries[at][ai + TrieNodeProto.VALUE_IDX];\n if (avi !== Trie.NULL) {\n mergeFn(avi, bvi);\n } else {\n tries[at][ai + TrieNodeProto.VALUE_IDX] = bvi;\n }\n }\n\n // Adjust to children property\n ai += TrieNodeProto.CHILDREN_IDX;\n bi += TrieNodeProto.CHILDREN_IDX;\n\n // Traverse right children\n const bn = bi + TrieNodeProto.CHILDREN_MEM;\n while (bi < bn) {\n // If right child is null\n let ri = tries[bt][bi + TriePointerProto.IDX_IDX];\n if (ri !== Trie.NULL) {\n // Resolve right child if redirect\n const rt = tries[bt][ri + TrieNodeProto.ID_IDX];\n if (bt !== rt) {\n ri = tries[bt][ri + TrieRedirectProto.IDX_IDX];\n }\n\n // If left child is null\n let li = tries[at][ai + TriePointerProto.IDX_IDX];\n if (li === Trie.NULL) {\n // Allocate redirect\n li = tries[at][TrieProto.SIZE_IDX];\n if (li + TrieRedirectProto.MEM > tries[at].length) {\n tries[at] = grow(tries[at], li + TrieRedirectProto.MEM);\n grown.push(at);\n }\n tries[at][TrieProto.SIZE_IDX] += TrieRedirectProto.MEM;\n // Attach redirect\n tries[at][ai + TriePointerProto.IDX_IDX] = li;\n // Initialize redirect\n tries[at][li + TrieRedirectProto.ID_IDX] = rt;\n tries[at][li + TrieRedirectProto.IDX_IDX] = ri;\n } else {\n // Resolve left child if redirect\n const lt = tries[at][li + TrieNodeProto.ID_IDX];\n if (at !== lt) {\n li = tries[at][li + TrieRedirectProto.IDX_IDX];\n }\n // Merge children\n queue.push([lt, li, rt, ri]);\n }\n }\n\n // Move to next children\n ai += TriePointerProto.MEM;\n bi += TriePointerProto.MEM;\n }\n }\n queue.splice(0, Q);\n } while (queue.length > 0);\n return grown;\n}\n\nexport function print(\n tries: Int32Array[],\n key: Buffer,\n trieIndex: number,\n stream: WriteStream,\n separator = \"\",\n callbackFn: (\n stream: WriteStream,\n key: Buffer,\n keyLen: number,\n valueIndex: number,\n ) => void,\n): void {\n const stack = new Array<[number, number, number]>(key.length + 1);\n stack[0] = [trieIndex, TrieProto.ROOT_IDX + TrieNodeProto.CHILDREN_IDX, 0];\n\n let top = 0;\n let tail = false;\n do {\n // eslint-disable-next-line prefer-const\n let [trieI, childPtr, numChild] = stack[top];\n\n // Check if end of children array\n if (numChild >= TrieNodeProto.CHILDREN_LEN) {\n --top;\n continue;\n }\n\n // Update stack top\n stack[top][1] += TriePointerProto.MEM;\n ++stack[top][2];\n\n // Check if child exists\n let childI = tries[trieI][childPtr + TriePointerProto.IDX_IDX];\n if (childI === Trie.NULL) {\n continue;\n }\n\n // Resolve redirect, if any\n const childTrieI = tries[trieI][childI + TrieNodeProto.ID_IDX];\n if (trieI !== childTrieI) {\n childI = tries[trieI][childI + TrieRedirectProto.IDX_IDX];\n trieI = childTrieI;\n }\n\n // Add the child to the stack\n key[top] = numChild + UTF8.BYTE_MIN;\n stack[++top] = [trieI, childI + TrieNodeProto.CHILDREN_IDX, 0];\n\n // Print value, if any\n const valueIndex = tries[trieI][childI + TrieNodeProto.VALUE_IDX];\n if (valueIndex !== Trie.NULL) {\n // Print separator if not first value\n if (tail) {\n stream.write(separator);\n }\n tail = true;\n callbackFn(stream, key, top, valueIndex);\n }\n } while (top >= 0);\n}\n", "import { Worker } from \"node:worker_threads\";\n\n/**\n * Creates a new Worker instance.\n *\n * @param workerPath - The path to the worker script.\n *\n * @returns A new Worker instance.\n */\nexport function createWorker(workerPath: string): Worker {\n const worker = new Worker(workerPath);\n worker.on(\"error\", (err) => {\n throw err;\n });\n worker.on(\"messageerror\", (err) => {\n throw err;\n });\n worker.on(\"exit\", (code) => {\n if (code > 1 || code < 0) {\n throw new Error(`Worker ${worker.threadId} exited with code ${code}`);\n }\n });\n return worker;\n}\n\n/**\n * Executes a task on a Worker and returns a Promise that resolves with the response.\n *\n * @param worker - The Worker instance to execute the task.\n * @param req - The request to send to the worker.\n *\n * @returns A Promise that resolves with the response from the worker.\n */\nexport function exec(worker: Worker, req: Req): Promise {\n return new Promise((resolve) => {\n worker.once(\"message\", resolve);\n worker.postMessage(req);\n });\n}\n", "import { readSync } from \"fs\";\n\nimport type { MergeRequest } from \"./types/mergeRequest\";\nimport type { MergeResponse } from \"./types/mergeResponse\";\nimport type { ProcessRequest } from \"./types/processRequest\";\nimport type { ProcessResponse } from \"./types/processResponse\";\n\nimport { BRC } from \"./constants/brc\";\nimport { CharCode, Trie, TrieNodeProto } from \"./constants/utf8\";\nimport { parseDouble } from \"./utils/parse\";\nimport { add, createTrie, mergeLeft } from \"./utils/utf8Trie\";\nimport { lastIndexOf } from \"./utils/stream\";\nimport { Config } from \"./constants/config\";\n\nexport function run({\n id,\n // I/O\n fd,\n fileSize,\n pageSize,\n chunkSize,\n // Shared memory\n counts,\n maxes,\n mins,\n page,\n sums,\n}: ProcessRequest): ProcessResponse {\n const newStation = (index: number, temp: number): void => {\n mins[index << 3] = temp;\n maxes[index << 3] = temp;\n counts[index << 2] = 1;\n sums[index << 1] = temp;\n };\n\n const updateStation = (index: number, temp: number): void => {\n index <<= 3;\n mins[index] = mins[index] <= temp ? mins[index] : temp;\n maxes[index] = maxes[index] >= temp ? maxes[index] : temp;\n ++counts[index >> 1];\n sums[index >> 2] += temp;\n };\n\n // Initialize constants\n const chunk = Buffer.allocUnsafe(chunkSize + Config.SYS_PAGE_SIZE);\n let stations = id * BRC.MAX_STATIONS;\n let trie = createTrie(id);\n\n // For each page\n // eslint-disable-next-line no-constant-condition\n while (true) {\n // Get page start\n let start = pageSize * Atomics.add(page, 0, 1);\n if (start >= fileSize) {\n break;\n }\n\n // Align start with entry\n let bufI = start > 0 ? Config.SYS_PAGE_SIZE : 0;\n readSync(fd, chunk, 0, bufI, start - bufI);\n let minI = lastIndexOf(chunk, CharCode.NEWLINE, bufI);\n\n // For each chunk\n const end = Math.min(fileSize, start + pageSize);\n for (++minI; start < end; start += chunkSize) {\n // Move incomplete entry to start of buffer\n let maxI = Config.SYS_PAGE_SIZE - bufI + minI;\n chunk.copyWithin(maxI, minI, bufI);\n bufI = Config.SYS_PAGE_SIZE;\n minI = maxI;\n\n // Read the chunk into memory\n maxI = Math.min(chunkSize, end - start);\n maxI = readSync(fd, chunk, bufI, maxI, start);\n\n // For each byte\n for (maxI += bufI; bufI < maxI; ++bufI) {\n // If not newline\n if (chunk[bufI] !== CharCode.NEWLINE) {\n continue;\n }\n\n // Get semicolon\n let semI = bufI - 5;\n if (chunk[semI] !== CharCode.SEMICOLON) {\n semI += 1 | (1 + ~(chunk[semI - 1] === CharCode.SEMICOLON));\n }\n\n // Add the station's name to the trie and get leaf\n let leaf: number;\n [trie, leaf] = add(trie, chunk, minI, semI);\n\n // Update next entry's min\n minI = bufI + 1;\n\n // Get temperature\n const temp = parseDouble(chunk, semI + 1, bufI);\n\n // If the station existed\n leaf += TrieNodeProto.VALUE_IDX;\n if (trie[leaf] !== Trie.NULL) {\n // Update the station's value\n updateStation(trie[leaf], temp);\n } else {\n // Add the new station's value\n trie[leaf] = ++stations;\n newStation(stations, temp);\n }\n }\n }\n }\n\n return { id, trie };\n}\n\nexport function merge({\n a,\n b,\n tries,\n counts,\n maxes,\n mins,\n sums,\n}: MergeRequest): MergeResponse {\n const ids = mergeLeft(tries, a, b, (ai: number, bi: number): void => {\n ai <<= 3;\n bi <<= 3;\n mins[ai] = mins[ai] <= mins[bi] ? mins[ai] : mins[bi];\n maxes[ai] = maxes[ai] >= maxes[bi] ? maxes[ai] : maxes[bi];\n counts[ai >> 1] += counts[bi >> 1];\n sums[ai >> 2] += sums[bi >> 2];\n });\n return { ids, tries };\n}\n", "import { CharCode } from \"../constants/utf8\";\n\nexport const CHAR_ZERO_11 = 11 * CharCode.ZERO;\nexport const CHAR_ZERO_111 = 111 * CharCode.ZERO;\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Fastest.\n */\nexport function parseDouble(b: Buffer, min: number, max: number): number {\n if (b[min] === CharCode.MINUS) {\n ++min;\n return min + 4 > max\n ? CHAR_ZERO_11 - 10 * b[min] - b[min + 2]\n : CHAR_ZERO_111 - 100 * b[min] - 10 * b[min + 1] - b[min + 3];\n }\n return min + 4 > max\n ? 10 * b[min] + b[min + 2] - CHAR_ZERO_11\n : 100 * b[min] + 10 * b[min + 1] + b[min + 3] - CHAR_ZERO_111;\n}\n\n/**\n * Converts an ASCII numeric string into an integer.\n *\n * Second fastest.\n */\nexport function parseDoubleFlat(b: Buffer, min: number, max: number): number {\n const sign = -(b[min] === CharCode.MINUS);\n b[min + ~sign] = CharCode.ZERO;\n return (\n ((100 * b[max - 4] + 10 * b[max - 3] + b[max - 1] - CHAR_ZERO_111) ^ sign) -\n sign\n );\n}\n\n/**\n * Converts an ASCII numeric string into an integer without branching.\n *\n * Inspired by {@link https://github.com/gunnarmorling/1brc/blob/main/src/main/java/dev/morling/onebrc/CalculateAverage_thomaswue.java#L68 | Quan Anh Mai's method}.\n *\n * Slowest.\n */\nexport function parseDoubleQuan(b: Buffer, min: number, max: number): number {\n b[min - 1] = 0;\n const sign = -(b[min] === CharCode.MINUS);\n const signMask = -(min + 4 >= max) & sign & 0xff000000;\n let v = b.readUint32BE(max - 4) & ~signMask & 0x0f0f000f;\n v = (v & 0xff000000) * 0x19 + (v & 0x00ff0000) * 0x280 + (v << 22);\n return ((v >>> 22) ^ sign) - sign;\n}\n"], - "mappings": "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", - "names": ["availableParallelism", "fileURLToPath", "isMainThread", "parentPort", "closeSync", "createWriteStream", "fstatSync", "openSync", "stdout", "clamp", "value", "min", "max", "getChunkSize", "size", "getPageSize", "fileSize", "workers", "lastIndexOf", "array", "searchElement", "add", "trie", "key", "min", "max", "index", "child", "grow", "createTrie", "id", "size", "trie", "grow", "minSize", "length", "next", "i", "mergeLeft", "tries", "at", "bt", "mergeFn", "grown", "queue", "Q", "q", "ai", "bi", "bvi", "avi", "bn", "ri", "rt", "li", "lt", "print", "key", "trieIndex", "stream", "separator", "callbackFn", "stack", "top", "tail", "trieI", "childPtr", "numChild", "childI", "childTrieI", "valueIndex", "Worker", "createWorker", "workerPath", "worker", "err", "code", "exec", "req", "resolve", "run", "filePath", "workerPath", "maxWorkers", "outPath", "clamp", "fd", "openSync", "fileSize", "fstatSync", "pageSize", "getPageSize", "chunkSize", "getChunkSize", "valBuf", "page", "mins", "maxes", "counts", "sums", "tries", "unmerged", "tasks", "i", "worker", "createWorker", "exec", "res", "a", "id", "closeSync", "out", "createWriteStream", "stdout", "buffer", "print", "printStation", "stream", "name", "nameLen", "vi", "avg", "readSync", "CHAR_ZERO_11", "CHAR_ZERO_111", "parseDouble", "b", "min", "max", "run", "id", "fd", "fileSize", "pageSize", "chunkSize", "counts", "maxes", "mins", "page", "sums", "newStation", "index", "temp", "updateStation", "chunk", "stations", "trie", "createTrie", "start", "bufI", "readSync", "minI", "lastIndexOf", "end", "maxI", "semI", "leaf", "add", "parseDouble", "merge", "a", "b", "tries", "mergeLeft", "ai", "bi", "isMainThread", "workerPath", "fileURLToPath", "run", "availableParallelism", "parentPort", "msg", "merge"] -} diff --git a/src/main/nodejs/havelessbemore/esbuild.config.js b/src/main/nodejs/havelessbemore/esbuild.config.js deleted file mode 100644 index c8d4707..0000000 --- a/src/main/nodejs/havelessbemore/esbuild.config.js +++ /dev/null @@ -1,19 +0,0 @@ -import * as esbuild from "esbuild"; - -import pkg from "./package.json" with { type: "json" }; - -/** @type {import('esbuild').BuildOptions} */ -const options = { - entryPoints: ["src/index.ts"], - bundle: true, - minify: true, - platform: "node", - sourcemap: true, - target: "ESNext", -}; - -await esbuild.build({ - ...options, - format: "esm", - outfile: pkg.module, -}); diff --git a/src/main/nodejs/havelessbemore/eslint.config.js b/src/main/nodejs/havelessbemore/eslint.config.js deleted file mode 100644 index 917eec7..0000000 --- a/src/main/nodejs/havelessbemore/eslint.config.js +++ /dev/null @@ -1,12 +0,0 @@ -import eslint from "@eslint/js"; -import prettierConfig from "eslint-config-prettier"; -import tseslint from "typescript-eslint"; - -/** @type {import('@typescript-eslint/utils').TSESLint.FlatConfig.ConfigArray} */ -export default tseslint.config( - { ignores: ["dist"] }, - eslint.configs.recommended, - ...tseslint.configs.recommended, - ...tseslint.configs.stylistic, - prettierConfig, -); diff --git a/src/main/nodejs/havelessbemore/eslint.config.mjs b/src/main/nodejs/havelessbemore/eslint.config.mjs new file mode 100644 index 0000000..d913e9a --- /dev/null +++ b/src/main/nodejs/havelessbemore/eslint.config.mjs @@ -0,0 +1,48 @@ +import js from "@eslint/js"; +import { defineConfig } from "eslint/config"; +import eslintConfigPrettier from "eslint-config-prettier/flat"; +import globals from "globals"; +import tseslint from "typescript-eslint"; + +// Ignore unused variables prefixed with an underscore +export const ignoreUnusedVariables = { + rules: { + "@typescript-eslint/no-unused-vars": [ + "error", + { + args: "all", + argsIgnorePattern: "^_", + caughtErrors: "all", + caughtErrorsIgnorePattern: "^_", + destructuredArrayIgnorePattern: "^_", + varsIgnorePattern: "^_", + ignoreRestSiblings: true, + }, + ], + }, +}; + +export default defineConfig([ + { + // Define global ignores. Must be used without + // any other keys in the configuration object. + ignores: ["dist", "package-lock.json", "tsconfig.json"], + }, + // Apply JavaScript rules + { + files: ["**/*.{js,mjs,cjs,ts}"], + plugins: { js }, + extends: ["js/recommended"], + }, + { + files: ["**/*.{js,mjs,cjs,ts}"], + languageOptions: { globals: globals.node }, + }, + // Apply TypeScript rules + tseslint.configs.recommended, + tseslint.configs.stylistic, + // Ignore unused variables prefixed with an underscore + ignoreUnusedVariables, + // Apply prettier rules + eslintConfigPrettier, +]); diff --git a/src/main/nodejs/havelessbemore/package-lock.json b/src/main/nodejs/havelessbemore/package-lock.json index ff95612..d82a4e4 100644 --- a/src/main/nodejs/havelessbemore/package-lock.json +++ b/src/main/nodejs/havelessbemore/package-lock.json @@ -1,429 +1,579 @@ { - "name": "havelessbemore", + "name": "1brc-nodejs", + "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { + "name": "1brc-nodejs", + "version": "1.0.0", "license": "MIT", "devDependencies": { - "@types/node": "^20.10.6", - "esbuild": "^0.21.4", - "eslint": "^8.57.0", - "eslint-config-prettier": "^9.1.0", - "prettier": "^3.2.5", - "rimraf": "^5.0.7", - "tinybench": "^2.8.0", - "tslib": "^2.6.2", - "tsx": "^4.10.5", - "typescript": "^5.4.5", - "typescript-eslint": "^7.10.0" + "@eslint/js": "^9.26.0", + "@eslint/json": "^0.12.0", + "@types/node": "^24.0.11", + "esbuild": "^0.25.4", + "eslint": "^9.26.0", + "eslint-config-prettier": "^10.1.5", + "globals": "^16.1.0", + "husky": "^9.1.7", + "prettier": "^3.5.3", + "tinybench": "^4.0.1", + "ts-node": "^10.9.2", + "tsup": "^8.5.0", + "typescript": "^5.8.3", + "typescript-eslint": "^8.32.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" }, "engines": { - "node": ">= 18" + "node": ">=12" } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.4.tgz", - "integrity": "sha512-Zrm+B33R4LWPLjDEVnEqt2+SLTATlru1q/xYKVn8oVTbiRBGmK2VIMoIYGJDGyftnGaC788IuzGFAlb7IQ0Y8A==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.6.tgz", + "integrity": "sha512-ShbM/3XxwuxjFiuVBHA+d3j5dyac0aEVVq1oluIDf71hUw0aRF59dV/efUsIwFnR6m8JNM2FjZOzmaZ8yG61kw==", "cpu": [ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "aix" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.4.tgz", - "integrity": "sha512-E7H/yTd8kGQfY4z9t3nRPk/hrhaCajfA3YSQSBrst8B+3uTcgsi8N+ZWYCaeIDsiVs6m65JPCaQN/DxBRclF3A==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.6.tgz", + "integrity": "sha512-S8ToEOVfg++AU/bHwdksHNnyLyVM+eMVAOf6yRKFitnwnbwwPNqKr3srzFRe7nzV69RQKb5DgchIX5pt3L53xg==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm64": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.4.tgz", - "integrity": "sha512-fYFnz+ObClJ3dNiITySBUx+oNalYUT18/AryMxfovLkYWbutXsct3Wz2ZWAcGGppp+RVVX5FiXeLYGi97umisA==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.6.tgz", + "integrity": "sha512-hd5zdUarsK6strW+3Wxi5qWws+rJhCCbMiC9QZyzoxfk5uHRIE8T287giQxzVpEvCwuJ9Qjg6bEjcRJcgfLqoA==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-x64": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.4.tgz", - "integrity": "sha512-mDqmlge3hFbEPbCWxp4fM6hqq7aZfLEHZAKGP9viq9wMUBVQx202aDIfc3l+d2cKhUJM741VrCXEzRFhPDKH3Q==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.6.tgz", + "integrity": "sha512-0Z7KpHSr3VBIO9A/1wcT3NTy7EB4oNC4upJ5ye3R7taCc2GUdeynSLArnon5G8scPwaU866d3H4BCrE5xLW25A==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.4.tgz", - "integrity": "sha512-72eaIrDZDSiWqpmCzVaBD58c8ea8cw/U0fq/PPOTqE3c53D0xVMRt2ooIABZ6/wj99Y+h4ksT/+I+srCDLU9TA==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.6.tgz", + "integrity": "sha512-FFCssz3XBavjxcFxKsGy2DYK5VSvJqa6y5HXljKzhRZ87LvEi13brPrf/wdyl/BbpbMKJNOr1Sd0jtW4Ge1pAA==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.4.tgz", - "integrity": "sha512-uBsuwRMehGmw1JC7Vecu/upOjTsMhgahmDkWhGLWxIgUn2x/Y4tIwUZngsmVb6XyPSTXJYS4YiASKPcm9Zitag==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.6.tgz", + "integrity": "sha512-GfXs5kry/TkGM2vKqK2oyiLFygJRqKVhawu3+DOCk7OxLy/6jYkWXhlHwOoTb0WqGnWGAS7sooxbZowy+pK9Yg==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.4.tgz", - "integrity": "sha512-8JfuSC6YMSAEIZIWNL3GtdUT5NhUA/CMUCpZdDRolUXNAXEE/Vbpe6qlGLpfThtY5NwXq8Hi4nJy4YfPh+TwAg==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.6.tgz", + "integrity": "sha512-aoLF2c3OvDn2XDTRvn8hN6DRzVVpDlj2B/F66clWd/FHLiHaG3aVZjxQX2DYphA5y/evbdGvC6Us13tvyt4pWg==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.4.tgz", - "integrity": "sha512-8d9y9eQhxv4ef7JmXny7591P/PYsDFc4+STaxC1GBv0tMyCdyWfXu2jBuqRsyhY8uL2HU8uPyscgE2KxCY9imQ==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.6.tgz", + "integrity": "sha512-2SkqTjTSo2dYi/jzFbU9Plt1vk0+nNg8YC8rOXXea+iA3hfNJWebKYPs3xnOUf9+ZWhKAaxnQNUf2X9LOpeiMQ==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.4.tgz", - "integrity": "sha512-2rqFFefpYmpMs+FWjkzSgXg5vViocqpq5a1PSRgT0AvSgxoXmGF17qfGAzKedg6wAwyM7UltrKVo9kxaJLMF/g==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.6.tgz", + "integrity": "sha512-SZHQlzvqv4Du5PrKE2faN0qlbsaW/3QQfUUc6yO2EjFcA83xnwm91UbEEVx4ApZ9Z5oG8Bxz4qPE+HFwtVcfyw==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.4.tgz", - "integrity": "sha512-/GLD2orjNU50v9PcxNpYZi+y8dJ7e7/LhQukN3S4jNDXCKkyyiyAz9zDw3siZ7Eh1tRcnCHAo/WcqKMzmi4eMQ==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.6.tgz", + "integrity": "sha512-b967hU0gqKd9Drsh/UuAm21Khpoh6mPBSgz8mKRq4P5mVK8bpA+hQzmm/ZwGVULSNBzKdZPQBRT3+WuVavcWsQ==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.4.tgz", - "integrity": "sha512-pNftBl7m/tFG3t2m/tSjuYeWIffzwAZT9m08+9DPLizxVOsUl8DdFzn9HvJrTQwe3wvJnwTdl92AonY36w/25g==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.6.tgz", + "integrity": "sha512-aHWdQ2AAltRkLPOsKdi3xv0mZ8fUGPdlKEjIEhxCPm5yKEThcUjHpWB1idN74lfXGnZ5SULQSgtr5Qos5B0bPw==", "cpu": [ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.4.tgz", - "integrity": "sha512-cSD2gzCK5LuVX+hszzXQzlWya6c7hilO71L9h4KHwqI4qeqZ57bAtkgcC2YioXjsbfAv4lPn3qe3b00Zt+jIfQ==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.6.tgz", + "integrity": "sha512-VgKCsHdXRSQ7E1+QXGdRPlQ/e08bN6WMQb27/TMfV+vPjjTImuT9PmLXupRlC90S1JeNNW5lzkAEO/McKeJ2yg==", "cpu": [ "loong64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.4.tgz", - "integrity": "sha512-qtzAd3BJh7UdbiXCrg6npWLYU0YpufsV9XlufKhMhYMJGJCdfX/G6+PNd0+v877X1JG5VmjBLUiFB0o8EUSicA==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.6.tgz", + "integrity": "sha512-WViNlpivRKT9/py3kCmkHnn44GkGXVdXfdc4drNmRl15zVQ2+D2uFwdlGh6IuK5AAnGTo2qPB1Djppj+t78rzw==", "cpu": [ "mips64el" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.4.tgz", - "integrity": "sha512-yB8AYzOTaL0D5+2a4xEy7OVvbcypvDR05MsB/VVPVA7nL4hc5w5Dyd/ddnayStDgJE59fAgNEOdLhBxjfx5+dg==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.6.tgz", + "integrity": "sha512-wyYKZ9NTdmAMb5730I38lBqVu6cKl4ZfYXIs31Baf8aoOtB4xSGi3THmDYt4BTFHk7/EcVixkOV2uZfwU3Q2Jw==", "cpu": [ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.4.tgz", - "integrity": "sha512-Y5AgOuVzPjQdgU59ramLoqSSiXddu7F3F+LI5hYy/d1UHN7K5oLzYBDZe23QmQJ9PIVUXwOdKJ/jZahPdxzm9w==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.6.tgz", + "integrity": "sha512-KZh7bAGGcrinEj4qzilJ4hqTY3Dg2U82c8bv+e1xqNqZCrCyc+TL9AUEn5WGKDzm3CfC5RODE/qc96OcbIe33w==", "cpu": [ "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.4.tgz", - "integrity": "sha512-Iqc/l/FFwtt8FoTK9riYv9zQNms7B8u+vAI/rxKuN10HgQIXaPzKZc479lZ0x6+vKVQbu55GdpYpeNWzjOhgbA==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.6.tgz", + "integrity": "sha512-9N1LsTwAuE9oj6lHMyyAM+ucxGiVnEqUdp4v7IaMmrwb06ZTEVCIs3oPPplVsnjPfyjmxwHxHMF8b6vzUVAUGw==", "cpu": [ "s390x" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-x64": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.4.tgz", - "integrity": "sha512-Td9jv782UMAFsuLZINfUpoF5mZIbAj+jv1YVtE58rFtfvoKRiKSkRGQfHTgKamLVT/fO7203bHa3wU122V/Bdg==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.6.tgz", + "integrity": "sha512-A6bJB41b4lKFWRKNrWoP2LHsjVzNiaurf7wyj/XtFNTsnPuxwEBWHLty+ZE0dWBKuSK1fvKgrKaNjBS7qbFKig==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.6.tgz", + "integrity": "sha512-IjA+DcwoVpjEvyxZddDqBY+uJ2Snc6duLpjmkXm/v4xuS3H+3FkLZlDm9ZsAbF9rsfP3zeA0/ArNDORZgrxR/Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.4.tgz", - "integrity": "sha512-Awn38oSXxsPMQxaV0Ipb7W/gxZtk5Tx3+W+rAPdZkyEhQ6968r9NvtkjhnhbEgWXYbgV+JEONJ6PcdBS+nlcpA==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.6.tgz", + "integrity": "sha512-dUXuZr5WenIDlMHdMkvDc1FAu4xdWixTCRgP7RQLBOkkGgwuuzaGSYcOpW4jFxzpzL1ejb8yF620UxAqnBrR9g==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "netbsd" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.6.tgz", + "integrity": "sha512-l8ZCvXP0tbTJ3iaqdNf3pjaOSd5ex/e6/omLIQCVBLmHTlfXW3zAxQ4fnDmPLOB1x9xrcSi/xtCWFwCZRIaEwg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.4.tgz", - "integrity": "sha512-IsUmQeCY0aU374R82fxIPu6vkOybWIMc3hVGZ3ChRwL9hA1TwY+tS0lgFWV5+F1+1ssuvvXt3HFqe8roCip8Hg==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.6.tgz", + "integrity": "sha512-hKrmDa0aOFOr71KQ/19JC7az1P0GWtCN1t2ahYAf4O007DHZt/dW8ym5+CUdJhQ/qkZmI1HAF8KkJbEFtCL7gw==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "openbsd" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.6.tgz", + "integrity": "sha512-+SqBcAWoB1fYKmpWoQP4pGtx+pUUC//RNYhFdbcSA16617cchuryuhOCRpPsjCblKukAckWsV+aQ3UKT/RMPcA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.4.tgz", - "integrity": "sha512-hsKhgZ4teLUaDA6FG/QIu2q0rI6I36tZVfM4DBZv3BG0mkMIdEnMbhc4xwLvLJSS22uWmaVkFkqWgIS0gPIm+A==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.6.tgz", + "integrity": "sha512-dyCGxv1/Br7MiSC42qinGL8KkG4kX0pEsdb0+TKhmJZgCUDBGmyo1/ArCjNGiOLiIAgdbWgmWgib4HoCi5t7kA==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "sunos" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.4.tgz", - "integrity": "sha512-UUfMgMoXPoA/bvGUNfUBFLCh0gt9dxZYIx9W4rfJr7+hKe5jxxHmfOK8YSH4qsHLLN4Ck8JZ+v7Q5fIm1huErg==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.6.tgz", + "integrity": "sha512-42QOgcZeZOvXfsCBJF5Afw73t4veOId//XD3i+/9gSkhSV6Gk3VPlWncctI+JcOyERv85FUo7RxuxGy+z8A43Q==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.4.tgz", - "integrity": "sha512-yIxbspZb5kGCAHWm8dexALQ9en1IYDfErzjSEq1KzXFniHv019VT3mNtTK7t8qdy4TwT6QYHI9sEZabONHg+aw==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.6.tgz", + "integrity": "sha512-4AWhgXmDuYN7rJI6ORB+uU9DHLq/erBbuMoAuB4VWJTu5KtCgcKYPynF0YI1VkBNuEfjNlLrFr9KZPJzrtLkrQ==", "cpu": [ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-x64": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.4.tgz", - "integrity": "sha512-sywLRD3UK/qRJt0oBwdpYLBibk7KiRfbswmWRDabuncQYSlf8aLEEUor/oP6KRz8KEG+HoiVLBhPRD5JWjS8Sg==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.6.tgz", + "integrity": "sha512-NgJPHHbEpLQgDH2MjQu90pzW/5vvXIZ7KOnPyNBm92A6WgZ/7b6fJyUBjoumLqeOQQGqY2QjQxRo97ah4Sj0cA==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", "dev": true, + "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.3" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, + "funding": { + "url": "https://opencollective.com/eslint" + }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", "dev": true, + "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, + "node_modules/@eslint/config-array": { + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", + "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.0.tgz", + "integrity": "sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.12.0.tgz", + "integrity": "sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", + "espree": "^10.0.1", + "globals": "^14.0.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.0", @@ -431,33 +581,127 @@ "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@eslint/js": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", - "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "version": "9.30.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.30.1.tgz", + "integrity": "sha512-zXhuECFlyep42KZUhWjfvsmXGX39W8K8LFb8AWXM9gSV9dQB+MrJGLKvW6Zw0Ggnbpw0VHTtrhFXYe3Gym18jg==", "dev": true, + "license": "MIT", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" } }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.11.14", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", - "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "node_modules/@eslint/json": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@eslint/json/-/json-0.12.0.tgz", + "integrity": "sha512-n/7dz8HFStpEe4o5eYk0tdkBdGUS/ZGb0GQCeDWN1ZmRq67HMHK4vC33b0rQlTT6xdZoX935P4vstiWVk5Ying==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@humanwhocodes/object-schema": "^2.0.2", - "debug": "^4.3.1", - "minimatch": "^3.0.5" + "@eslint/core": "^0.12.0", + "@eslint/plugin-kit": "^0.2.7", + "@humanwhocodes/momoa": "^3.3.4", + "natural-compare": "^1.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz", + "integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.13.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit/node_modules/@eslint/core": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz", + "integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" }, "engines": { - "node": ">=10.10.0" + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, "node_modules/@humanwhocodes/module-importer": { @@ -465,6 +709,7 @@ "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=12.22" }, @@ -473,17 +718,36 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "dev": true + "node_modules/@humanwhocodes/momoa": { + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/momoa/-/momoa-3.3.8.tgz", + "integrity": "sha512-/3PZzor2imi/RLLcnHztkwA79txiVvW145Ve2cp5dxRcH5qOUNJPToasqLFHniTfw4B4lT7jGDdBOPXbXYlIMQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, + "license": "ISC", "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -496,31 +760,54 @@ "node": ">=12" } }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", + "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "node_modules/@jridgewell/gen-mapping/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.29", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", + "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-regex": "^6.0.1" - }, + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", + "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" } }, "node_modules/@nodelib/fs.scandir": { @@ -528,6 +815,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -541,6 +829,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } @@ -550,6 +839,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -563,132 +853,498 @@ "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", "dev": true, + "license": "MIT", "optional": true, "engines": { "node": ">=14" } }, - "node_modules/@types/node": { - "version": "20.12.12", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.12.tgz", - "integrity": "sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw==", + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.44.2.tgz", + "integrity": "sha512-g0dF8P1e2QYPOj1gu7s/3LVP6kze9A7m6x0BZ9iTdXK8N5c2V7cpBKHV3/9A4Zd8xxavdhK0t4PnqjkqVmUc9Q==", + "cpu": [ + "arm" + ], "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } + "license": "MIT", + "optional": true, + "os": [ + "android" + ] }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.10.0.tgz", - "integrity": "sha512-PzCr+a/KAef5ZawX7nbyNwBDtM1HdLIT53aSA2DDlxmxMngZ43O8SIePOeX8H5S+FHXeI6t97mTt/dDdzY4Fyw==", + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.44.2.tgz", + "integrity": "sha512-Yt5MKrOosSbSaAK5Y4J+vSiID57sOvpBNBR6K7xAaQvk3MkcNVV0f9fE20T+41WYN8hDn6SGFlFrKudtx4EoxA==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.10.0", - "@typescript-eslint/type-utils": "7.10.0", - "@typescript-eslint/utils": "7.10.0", - "@typescript-eslint/visitor-keys": "7.10.0", - "graphemer": "^1.4.0", - "ignore": "^5.3.1", - "natural-compare": "^1.4.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || >=20.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^7.0.0", - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.44.2.tgz", + "integrity": "sha512-EsnFot9ZieM35YNA26nhbLTJBHD0jTwWpPwmRVDzjylQT6gkar+zenfb8mHxWpRrbn+WytRRjE0WKsfaxBkVUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.44.2.tgz", + "integrity": "sha512-dv/t1t1RkCvJdWWxQ2lWOO+b7cMsVw5YFaS04oHpZRWehI1h0fV1gF4wgGCTyQHHjJDfbNpwOi6PXEafRBBezw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.44.2.tgz", + "integrity": "sha512-W4tt4BLorKND4qeHElxDoim0+BsprFTwb+vriVQnFFtT/P6v/xO5I99xvYnVzKWrK6j7Hb0yp3x7V5LUbaeOMg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.44.2.tgz", + "integrity": "sha512-tdT1PHopokkuBVyHjvYehnIe20fxibxFCEhQP/96MDSOcyjM/shlTkZZLOufV3qO6/FQOSiJTBebhVc12JyPTA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.44.2.tgz", + "integrity": "sha512-+xmiDGGaSfIIOXMzkhJ++Oa0Gwvl9oXUeIiwarsdRXSe27HUIvjbSIpPxvnNsRebsNdUo7uAiQVgBD1hVriwSQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.44.2.tgz", + "integrity": "sha512-bDHvhzOfORk3wt8yxIra8N4k/N0MnKInCW5OGZaeDYa/hMrdPaJzo7CSkjKZqX4JFUWjUGm88lI6QJLCM7lDrA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.44.2.tgz", + "integrity": "sha512-NMsDEsDiYghTbeZWEGnNi4F0hSbGnsuOG+VnNvxkKg0IGDvFh7UVpM/14mnMwxRxUf9AdAVJgHPvKXf6FpMB7A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.44.2.tgz", + "integrity": "sha512-lb5bxXnxXglVq+7imxykIp5xMq+idehfl+wOgiiix0191av84OqbjUED+PRC5OA8eFJYj5xAGcpAZ0pF2MnW+A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.44.2.tgz", + "integrity": "sha512-Yl5Rdpf9pIc4GW1PmkUGHdMtbx0fBLE1//SxDmuf3X0dUC57+zMepow2LK0V21661cjXdTn8hO2tXDdAWAqE5g==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.44.2.tgz", + "integrity": "sha512-03vUDH+w55s680YYryyr78jsO1RWU9ocRMaeV2vMniJJW/6HhoTBwyyiiTPVHNWLnhsnwcQ0oH3S9JSBEKuyqw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.44.2.tgz", + "integrity": "sha512-iYtAqBg5eEMG4dEfVlkqo05xMOk6y/JXIToRca2bAWuqjrJYJlx/I7+Z+4hSrsWU8GdJDFPL4ktV3dy4yBSrzg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.44.2.tgz", + "integrity": "sha512-e6vEbgaaqz2yEHqtkPXa28fFuBGmUJ0N2dOJK8YUfijejInt9gfCSA7YDdJ4nYlv67JfP3+PSWFX4IVw/xRIPg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.44.2.tgz", + "integrity": "sha512-evFOtkmVdY3udE+0QKrV5wBx7bKI0iHz5yEVx5WqDJkxp9YQefy4Mpx3RajIVcM6o7jxTvVd/qpC1IXUhGc1Mw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.44.2.tgz", + "integrity": "sha512-/bXb0bEsWMyEkIsUL2Yt5nFB5naLAwyOWMEviQfQY1x3l5WsLKgvZf66TM7UTfED6erckUVUJQ/jJ1FSpm3pRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.44.2.tgz", + "integrity": "sha512-3D3OB1vSSBXmkGEZR27uiMRNiwN08/RVAcBKwhUYPaiZ8bcvdeEwWPvbnXvvXHY+A/7xluzcN+kaiOFNiOZwWg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.44.2.tgz", + "integrity": "sha512-VfU0fsMK+rwdK8mwODqYeM2hDrF2WiHaSmCBrS7gColkQft95/8tphyzv2EupVxn3iE0FI78wzffoULH1G+dkw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.44.2.tgz", + "integrity": "sha512-+qMUrkbUurpE6DVRjiJCNGZBGo9xM4Y0FXU5cjgudWqIBWbcLkjE3XprJUsOFgC6xjBClwVa9k6O3A7K3vxb5Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.44.2.tgz", + "integrity": "sha512-3+QZROYfJ25PDcxFF66UEk8jGWigHJeecZILvkPkyQN7oc5BvFo4YEXFkOs154j3FTMp9mn9Ky8RCOwastduEA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.0.13", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.13.tgz", + "integrity": "sha512-Qm9OYVOFHFYg3wJoTSrz80hoec5Lia/dPp84do3X7dZvLikQvM1YpmvTBEdIr/e+U8HTkFjLHLnl78K/qjf+jQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.8.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.36.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.36.0.tgz", + "integrity": "sha512-lZNihHUVB6ZZiPBNgOQGSxUASI7UJWhT8nHyUGCnaQ28XFCw98IfrMCG3rUl1uwUWoAvodJQby2KTs79UTcrAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.36.0", + "@typescript-eslint/type-utils": "8.36.0", + "@typescript-eslint/utils": "8.36.0", + "@typescript-eslint/visitor-keys": "8.36.0", + "graphemer": "^1.4.0", + "ignore": "^7.0.0", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.36.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } }, "node_modules/@typescript-eslint/parser": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.10.0.tgz", - "integrity": "sha512-2EjZMA0LUW5V5tGQiaa2Gys+nKdfrn2xiTIBLR4fxmPmVSvgPcKNW+AE/ln9k0A4zDUti0J/GZXMDupQoI+e1w==", + "version": "8.36.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.36.0.tgz", + "integrity": "sha512-FuYgkHwZLuPbZjQHzJXrtXreJdFMKl16BFYyRrLxDhWr6Qr7Kbcu2s1Yhu8tsiMXw1S0W1pjfFfYEt+R604s+Q==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "7.10.0", - "@typescript-eslint/types": "7.10.0", - "@typescript-eslint/typescript-estree": "7.10.0", - "@typescript-eslint/visitor-keys": "7.10.0", + "@typescript-eslint/scope-manager": "8.36.0", + "@typescript-eslint/types": "8.36.0", + "@typescript-eslint/typescript-estree": "8.36.0", + "@typescript-eslint/visitor-keys": "8.36.0", "debug": "^4.3.4" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.56.0" + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.36.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.36.0.tgz", + "integrity": "sha512-JAhQFIABkWccQYeLMrHadu/fhpzmSQ1F1KXkpzqiVxA/iYI6UnRt2trqXHt1sYEcw1mxLnB9rKMsOxXPxowN/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.36.0", + "@typescript-eslint/types": "^8.36.0", + "debug": "^4.3.4" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.10.0.tgz", - "integrity": "sha512-7L01/K8W/VGl7noe2mgH0K7BE29Sq6KAbVmxurj8GGaPDZXPr8EEQ2seOeAS+mEV9DnzxBQB6ax6qQQ5C6P4xg==", + "version": "8.36.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.36.0.tgz", + "integrity": "sha512-wCnapIKnDkN62fYtTGv2+RY8FlnBYA3tNm0fm91kc2BjPhV2vIjwwozJ7LToaLAyb1ca8BxrS7vT+Pvvf7RvqA==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.10.0", - "@typescript-eslint/visitor-keys": "7.10.0" + "@typescript-eslint/types": "8.36.0", + "@typescript-eslint/visitor-keys": "8.36.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.36.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.36.0.tgz", + "integrity": "sha512-Nhh3TIEgN18mNbdXpd5Q8mSCBnrZQeY9V7Ca3dqYvNDStNIGRmJA6dmrIPMJ0kow3C7gcQbpsG2rPzy1Ks/AnA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.10.0.tgz", - "integrity": "sha512-D7tS4WDkJWrVkuzgm90qYw9RdgBcrWmbbRkrLA4d7Pg3w0ttVGDsvYGV19SH8gPR5L7OtcN5J1hTtyenO9xE9g==", + "version": "8.36.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.36.0.tgz", + "integrity": "sha512-5aaGYG8cVDd6cxfk/ynpYzxBRZJk7w/ymto6uiyUFtdCozQIsQWh7M28/6r57Fwkbweng8qAzoMCPwSJfWlmsg==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "7.10.0", - "@typescript-eslint/utils": "7.10.0", + "@typescript-eslint/typescript-estree": "8.36.0", + "@typescript-eslint/utils": "8.36.0", "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" + "ts-api-utils": "^2.1.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/types": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.10.0.tgz", - "integrity": "sha512-7fNj+Ya35aNyhuqrA1E/VayQX9Elwr8NKZ4WueClR3KwJ7Xx9jcCdOrLW04h51de/+gNbyFMs+IDxh5xIwfbNg==", + "version": "8.36.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.36.0.tgz", + "integrity": "sha512-xGms6l5cTJKQPZOKM75Dl9yBfNdGeLRsIyufewnxT4vZTrjC0ImQT4fj8QmtJK84F58uSh5HVBSANwcfiXxABQ==", "dev": true, + "license": "MIT", "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", @@ -696,47 +1352,50 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.10.0.tgz", - "integrity": "sha512-LXFnQJjL9XIcxeVfqmNj60YhatpRLt6UhdlFwAkjNc6jSUlK8zQOl1oktAP8PlWFzPQC1jny/8Bai3/HPuvN5g==", + "version": "8.36.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.36.0.tgz", + "integrity": "sha512-JaS8bDVrfVJX4av0jLpe4ye0BpAaUW7+tnS4Y4ETa3q7NoZgzYbN9zDQTJ8kPb5fQ4n0hliAt9tA4Pfs2zA2Hg==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.10.0", - "@typescript-eslint/visitor-keys": "7.10.0", + "@typescript-eslint/project-service": "8.36.0", + "@typescript-eslint/tsconfig-utils": "8.36.0", + "@typescript-eslint/types": "8.36.0", + "@typescript-eslint/visitor-keys": "8.36.0", "debug": "^4.3.4", - "globby": "^11.1.0", + "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" + "ts-api-utils": "^2.1.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -748,55 +1407,53 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.10.0.tgz", - "integrity": "sha512-olzif1Fuo8R8m/qKkzJqT7qwy16CzPRWBvERS0uvyc+DHd8AKbO4Jb7kpAvVzMmZm8TrHnI7hvjN4I05zow+tg==", + "version": "8.36.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.36.0.tgz", + "integrity": "sha512-VOqmHu42aEMT+P2qYjylw6zP/3E/HvptRwdn/PZxyV27KhZg2IOszXod4NcXisWzPAGSS4trE/g4moNj6XmH2g==", "dev": true, + "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "7.10.0", - "@typescript-eslint/types": "7.10.0", - "@typescript-eslint/typescript-estree": "7.10.0" + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.36.0", + "@typescript-eslint/types": "8.36.0", + "@typescript-eslint/typescript-estree": "8.36.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.56.0" + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.10.0.tgz", - "integrity": "sha512-9ntIVgsi6gg6FIq9xjEO4VQJvwOqA3jaBFQJ/6TK5AvEup2+cECI6Fh7QiBxmfMHXU0V0J4RyPeOU1VDNzl9cg==", + "version": "8.36.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.36.0.tgz", + "integrity": "sha512-vZrhV2lRPWDuGoxcmrzRZyxAggPL+qp3WzUrlZD+slFueDiYHxeBa34dUXPuC0RmGKzl4lS5kFJYvKCq9cnNDA==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "7.10.0", - "eslint-visitor-keys": "^3.4.3" + "@typescript-eslint/types": "8.36.0", + "eslint-visitor-keys": "^4.2.1" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -809,15 +1466,30 @@ "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, + "license": "MIT", "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "license": "MIT", "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -830,12 +1502,16 @@ } }, "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, "node_modules/ansi-styles": { @@ -843,6 +1519,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, @@ -853,32 +1530,40 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true, + "license": "MIT" + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true, - "engines": { - "node": ">=8" - } + "license": "Python-2.0" }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -889,6 +1574,7 @@ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { "fill-range": "^7.1.1" }, @@ -896,11 +1582,38 @@ "node": ">=8" } }, + "node_modules/bundle-require": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/bundle-require/-/bundle-require-5.1.0.tgz", + "integrity": "sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "load-tsconfig": "^0.2.3" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "peerDependencies": { + "esbuild": ">=0.18" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -910,6 +1623,7 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -921,11 +1635,28 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, + "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, @@ -937,19 +1668,56 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/consola": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", + "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^14.18.0 || >=16.10.0" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, + "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -960,12 +1728,13 @@ } }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", "dev": true, + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -980,80 +1749,73 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } + "license": "MIT" }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, + "license": "BSD-3-Clause", "engines": { - "node": ">=6.0.0" + "node": ">=0.3.1" } }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/esbuild": { - "version": "0.21.4", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.4.tgz", - "integrity": "sha512-sFMcNNrj+Q0ZDolrp5pDhH0nRPN9hLIM3fRPwgbLYJeSHHgnXSnbV3xYgSVuOeLWH9c73VwmEverVzupIv5xuA==", + "version": "0.25.6", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.6.tgz", + "integrity": "sha512-GVuzuUwtdsghE3ocJ9Bs8PNoF13HNQ5TXbEi2AhvVb8xU1Iwt9Fos9FEamfoee+u/TOsn7GUWc04lz46n2bbTg==", "dev": true, "hasInstallScript": true, + "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.4", - "@esbuild/android-arm": "0.21.4", - "@esbuild/android-arm64": "0.21.4", - "@esbuild/android-x64": "0.21.4", - "@esbuild/darwin-arm64": "0.21.4", - "@esbuild/darwin-x64": "0.21.4", - "@esbuild/freebsd-arm64": "0.21.4", - "@esbuild/freebsd-x64": "0.21.4", - "@esbuild/linux-arm": "0.21.4", - "@esbuild/linux-arm64": "0.21.4", - "@esbuild/linux-ia32": "0.21.4", - "@esbuild/linux-loong64": "0.21.4", - "@esbuild/linux-mips64el": "0.21.4", - "@esbuild/linux-ppc64": "0.21.4", - "@esbuild/linux-riscv64": "0.21.4", - "@esbuild/linux-s390x": "0.21.4", - "@esbuild/linux-x64": "0.21.4", - "@esbuild/netbsd-x64": "0.21.4", - "@esbuild/openbsd-x64": "0.21.4", - "@esbuild/sunos-x64": "0.21.4", - "@esbuild/win32-arm64": "0.21.4", - "@esbuild/win32-ia32": "0.21.4", - "@esbuild/win32-x64": "0.21.4" + "@esbuild/aix-ppc64": "0.25.6", + "@esbuild/android-arm": "0.25.6", + "@esbuild/android-arm64": "0.25.6", + "@esbuild/android-x64": "0.25.6", + "@esbuild/darwin-arm64": "0.25.6", + "@esbuild/darwin-x64": "0.25.6", + "@esbuild/freebsd-arm64": "0.25.6", + "@esbuild/freebsd-x64": "0.25.6", + "@esbuild/linux-arm": "0.25.6", + "@esbuild/linux-arm64": "0.25.6", + "@esbuild/linux-ia32": "0.25.6", + "@esbuild/linux-loong64": "0.25.6", + "@esbuild/linux-mips64el": "0.25.6", + "@esbuild/linux-ppc64": "0.25.6", + "@esbuild/linux-riscv64": "0.25.6", + "@esbuild/linux-s390x": "0.25.6", + "@esbuild/linux-x64": "0.25.6", + "@esbuild/netbsd-arm64": "0.25.6", + "@esbuild/netbsd-x64": "0.25.6", + "@esbuild/openbsd-arm64": "0.25.6", + "@esbuild/openbsd-x64": "0.25.6", + "@esbuild/openharmony-arm64": "0.25.6", + "@esbuild/sunos-x64": "0.25.6", + "@esbuild/win32-arm64": "0.25.6", + "@esbuild/win32-ia32": "0.25.6", + "@esbuild/win32-x64": "0.25.6" } }, "node_modules/escape-string-regexp": { @@ -1061,6 +1823,7 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, @@ -1069,122 +1832,176 @@ } }, "node_modules/eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", - "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "version": "9.30.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.30.1.tgz", + "integrity": "sha512-zmxXPNMOXmwm9E0yQLi5uqXHs7uq2UIiqEKo3Gq+3fwo1XrJ+hijAZImyF7hclW3E6oHz43Yk3RP8at6OTKflQ==", "dev": true, + "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.0", - "@humanwhocodes/config-array": "^0.11.14", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.0", + "@eslint/config-helpers": "^0.3.0", + "@eslint/core": "^0.14.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.30.1", + "@eslint/plugin-kit": "^0.3.1", + "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", "ajv": "^6.12.4", "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", + "cross-spawn": "^7.0.6", "debug": "^4.3.2", - "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^8.0.0", "find-up": "^5.0.0", "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" + "optionator": "^0.9.3" }, "bin": { "eslint": "bin/eslint.js" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } } }, "node_modules/eslint-config-prettier": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", - "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "version": "10.1.5", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.5.tgz", + "integrity": "sha512-zc1UmCpNltmVY34vuLRV61r1K27sWuX39E+uyUnY8xS2Bex88VV9cugG+UZbRSRGtGyFboj+D8JODyme1plMpw==", "dev": true, + "license": "MIT", "bin": { "eslint-config-prettier": "bin/cli.js" }, + "funding": { + "url": "https://opencollective.com/eslint-config-prettier" + }, "peerDependencies": { "eslint": ">=7.0.0" } }, "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", "dev": true, + "license": "Apache-2.0", "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/@eslint/core": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.14.0.tgz", + "integrity": "sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/eslint/node_modules/@eslint/plugin-kit": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.3.tgz", + "integrity": "sha512-1+WqvgNMhmlAambTvT3KPtCl/Ibr68VldY2XY40SL1CE0ZXiakFR/cbTspaF5HsnpDMvcYYoJHfl4980NBjGag==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.15.1", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/eslint/node_modules/@eslint/plugin-kit/node_modules/@eslint/core": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.1.tgz", + "integrity": "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "acorn": "^8.9.0", + "acorn": "^8.15.0", "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" + "eslint-visitor-keys": "^4.2.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "url": "https://opencollective.com/eslint" } }, "node_modules/esquery": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", - "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" }, @@ -1197,6 +2014,7 @@ "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" }, @@ -1209,6 +2027,7 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=4.0" } @@ -1218,6 +2037,7 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, + "license": "BSD-2-Clause", "engines": { "node": ">=0.10.0" } @@ -1226,19 +2046,21 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "micromatch": "^4.0.8" }, "engines": { "node": ">=8.6.0" @@ -1249,6 +2071,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, @@ -1260,33 +2083,52 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fdir": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", "dev": true, - "dependencies": { - "reusify": "^1.0.4" + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } } }, "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, + "license": "MIT", "dependencies": { - "flat-cache": "^3.0.4" + "flat-cache": "^4.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=16.0.0" } }, "node_modules/fill-range": { @@ -1294,6 +2136,7 @@ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -1306,6 +2149,7 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, + "license": "MIT", "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -1317,68 +2161,47 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "node_modules/fix-dts-default-cjs-exports": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fix-dts-default-cjs-exports/-/fix-dts-default-cjs-exports-1.0.1.tgz", + "integrity": "sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==", "dev": true, + "license": "MIT", "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" + "magic-string": "^0.30.17", + "mlly": "^1.7.4", + "rollup": "^4.34.8" } }, - "node_modules/flat-cache/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, + "license": "MIT", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "flatted": "^3.2.9", + "keyv": "^4.5.4" }, "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/flat-cache/node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=16" } }, "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" }, "node_modules/foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", "dev": true, + "license": "ISC", "dependencies": { - "cross-spawn": "^7.0.0", + "cross-spawn": "^7.0.6", "signal-exit": "^4.0.1" }, "engines": { @@ -1388,18 +2211,13 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true - }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -1408,36 +2226,23 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/get-tsconfig": { - "version": "4.7.5", - "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.5.tgz", - "integrity": "sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==", - "dev": true, - "dependencies": { - "resolve-pkg-maps": "^1.0.0" - }, - "funding": { - "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" - } - }, "node_modules/glob": { - "version": "10.3.15", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.15.tgz", - "integrity": "sha512-0c6RlJt1TICLyvJYIApxb8GsXoai0KUP7AxKKAtsYXdgJR1mGEUa7DgwShbdk1nly0PYoZj01xd4hzbq3fsjpw==", + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, + "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", - "jackspeak": "^2.3.6", - "minimatch": "^9.0.1", - "minipass": "^7.0.4", - "path-scurry": "^1.11.0" + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" }, "bin": { "glob": "dist/esm/bin.mjs" }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, "funding": { "url": "https://github.com/sponsors/isaacs" } @@ -1447,6 +2252,7 @@ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, + "license": "ISC", "dependencies": { "is-glob": "^4.0.3" }, @@ -1455,19 +2261,21 @@ } }, "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/glob/node_modules/minimatch": { - "version": "9.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", - "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -1479,35 +2287,13 @@ } }, "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "version": "16.3.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.3.0.tgz", + "integrity": "sha512-bqWEnJ1Nt3neqx2q5SFfGS8r/ahumIakg3HcwtNlrVlwXIeNumWn/c7Pn/wKzGhf6SaW6H6uWXLqC30STCMchQ==", "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -1517,31 +2303,51 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, + "node_modules/husky": { + "version": "9.1.7", + "resolved": "https://registry.npmjs.org/husky/-/husky-9.1.7.tgz", + "integrity": "sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==", + "dev": true, + "license": "MIT", + "bin": { + "husky": "bin.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/typicode" + } + }, "node_modules/ignore": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", - "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } }, "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, + "license": "MIT", "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -1558,31 +2364,17 @@ "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.8.19" } }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -1592,6 +2384,7 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -1601,6 +2394,7 @@ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, + "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, @@ -1613,36 +2407,27 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "dev": true, + "license": "ISC" }, "node_modules/jackspeak": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", - "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" }, - "engines": { - "node": ">=14" - }, "funding": { "url": "https://github.com/sponsors/isaacs" }, @@ -1650,11 +2435,22 @@ "@pkgjs/parseargs": "^0.11.0" } }, + "node_modules/joycon": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", + "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -1666,25 +2462,29 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, + "license": "MIT", "dependencies": { "json-buffer": "3.0.1" } @@ -1694,6 +2494,7 @@ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -1702,11 +2503,42 @@ "node": ">= 0.8.0" } }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/load-tsconfig": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/load-tsconfig/-/load-tsconfig-0.2.5.tgz", + "integrity": "sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^5.0.0" }, @@ -1721,46 +2553,72 @@ "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==", + "dev": true, + "license": "MIT" }, "node_modules/lru-cache": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz", - "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==", + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", "dev": true, - "engines": { - "node": "14 || >=16.14" + "license": "ISC" + }, + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } }, "node_modules/micromatch": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.6.tgz", - "integrity": "sha512-Y4Ypn3oujJYxJcMacVgcs92wofTHxp9FzfDpQON4msDefoC0lb3ETvQLOdLcbhSwU1bz8HrL/1sygfBIHudrkQ==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, + "license": "MIT", "dependencies": { "braces": "^3.0.3", - "picomatch": "^4.0.2" + "picomatch": "^2.3.1" }, "engines": { "node": ">=8.6" } }, "node_modules/micromatch/node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=8.6" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" @@ -1771,6 +2629,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -1779,33 +2638,62 @@ } }, "node_modules/minipass": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.1.tgz", - "integrity": "sha512-UZ7eQ+h8ywIRAW1hIEl2AqdwzJucU/Kp59+8kkZeSvafXhZjul247BvIJjEVFVeON6d7lM46XX1HXCduKAS8VA==", + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", "dev": true, + "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" } }, + "node_modules/mlly": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.4.tgz", + "integrity": "sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.14.0", + "pathe": "^2.0.1", + "pkg-types": "^1.3.0", + "ufo": "^1.5.4" + } + }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true + "dev": true, + "license": "MIT" }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "dev": true, - "dependencies": { - "wrappy": "1" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, "node_modules/optionator": { @@ -1813,6 +2701,7 @@ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, + "license": "MIT", "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", @@ -1830,6 +2719,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" }, @@ -1845,6 +2735,7 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, + "license": "MIT", "dependencies": { "p-limit": "^3.0.2" }, @@ -1855,11 +2746,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "dev": true, + "license": "BlueOak-1.0.0" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, + "license": "MIT", "dependencies": { "callsites": "^3.0.0" }, @@ -1872,24 +2771,17 @@ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -1899,6 +2791,7 @@ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", "dev": true, + "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -1910,13 +2803,96 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, + "node_modules/postcss-load-config": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", + "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.1.1" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "jiti": ">=1.21.0", + "postcss": ">=8.0.9", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + }, + "postcss": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } } }, "node_modules/prelude-ls": { @@ -1924,15 +2900,17 @@ "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.8.0" } }, "node_modules/prettier": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", - "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", + "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", "dev": true, + "license": "MIT", "bin": { "prettier": "bin/prettier.cjs" }, @@ -1948,6 +2926,7 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, + "license": "MIT", "engines": { "node": ">=6" } @@ -1970,52 +2949,82 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } }, "node_modules/resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } }, - "node_modules/resolve-pkg-maps": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", - "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", - "dev": true, - "funding": { - "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" - } - }, "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "dev": true, + "license": "MIT", "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" } }, - "node_modules/rimraf": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.7.tgz", - "integrity": "sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==", + "node_modules/rollup": { + "version": "4.44.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.44.2.tgz", + "integrity": "sha512-PVoapzTwSEcelaWGth3uR66u7ZRo6qhPHc0f2uRO9fX6XDVNrIiGYS0Pj9+R8yIIYSD/mCx2b16Ws9itljKSPg==", "dev": true, + "license": "MIT", "dependencies": { - "glob": "^10.3.7" + "@types/estree": "1.0.8" }, "bin": { - "rimraf": "dist/esm/bin.mjs" + "rollup": "dist/bin/rollup" }, "engines": { - "node": ">=14.18" + "node": ">=18.0.0", + "npm": ">=8.0.0" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.44.2", + "@rollup/rollup-android-arm64": "4.44.2", + "@rollup/rollup-darwin-arm64": "4.44.2", + "@rollup/rollup-darwin-x64": "4.44.2", + "@rollup/rollup-freebsd-arm64": "4.44.2", + "@rollup/rollup-freebsd-x64": "4.44.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.44.2", + "@rollup/rollup-linux-arm-musleabihf": "4.44.2", + "@rollup/rollup-linux-arm64-gnu": "4.44.2", + "@rollup/rollup-linux-arm64-musl": "4.44.2", + "@rollup/rollup-linux-loongarch64-gnu": "4.44.2", + "@rollup/rollup-linux-powerpc64le-gnu": "4.44.2", + "@rollup/rollup-linux-riscv64-gnu": "4.44.2", + "@rollup/rollup-linux-riscv64-musl": "4.44.2", + "@rollup/rollup-linux-s390x-gnu": "4.44.2", + "@rollup/rollup-linux-x64-gnu": "4.44.2", + "@rollup/rollup-linux-x64-musl": "4.44.2", + "@rollup/rollup-win32-arm64-msvc": "4.44.2", + "@rollup/rollup-win32-ia32-msvc": "4.44.2", + "@rollup/rollup-win32-x64-msvc": "4.44.2", + "fsevents": "~2.3.2" } }, "node_modules/run-parallel": { @@ -2037,15 +3046,17 @@ "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } }, "node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", "dev": true, + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -2058,6 +3069,7 @@ "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, + "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, @@ -2070,6 +3082,7 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -2079,6 +3092,7 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, + "license": "ISC", "engines": { "node": ">=14" }, @@ -2086,13 +3100,17 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "node_modules/source-map": { + "version": "0.8.0-beta.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", + "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "whatwg-url": "^7.0.0" + }, "engines": { - "node": ">=8" + "node": ">= 8" } }, "node_modules/string-width": { @@ -2100,6 +3118,7 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, + "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -2118,6 +3137,7 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -2127,29 +3147,42 @@ "node": ">=8" } }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/string-width-cjs/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "dev": true, + "license": "MIT" }, - "node_modules/string-width/node_modules/ansi-regex": { + "node_modules/string-width-cjs/node_modules/strip-ansi": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, - "engines": { - "node": ">=12" + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "engines": { + "node": ">=8" } }, - "node_modules/string-width/node_modules/strip-ansi": { + "node_modules/strip-ansi": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -2160,11 +3193,13 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/strip-ansi": { + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -2172,15 +3207,12 @@ "node": ">=8" } }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, + "license": "MIT", "engines": { "node": ">=8" } @@ -2190,6 +3222,7 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -2197,483 +3230,257 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/tinybench": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.8.0.tgz", - "integrity": "sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw==", - "dev": true - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/ts-api-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", - "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", - "dev": true, - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, - "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "dev": true - }, - "node_modules/tsx": { - "version": "4.10.5", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.10.5.tgz", - "integrity": "sha512-twDSbf7Gtea4I2copqovUiNTEDrT8XNFXsuHpfGbdpW/z9ZW4fTghzzhAG0WfrCuJmJiOEY1nLIjq4u3oujRWQ==", - "dev": true, - "dependencies": { - "esbuild": "~0.20.2", - "get-tsconfig": "^4.7.5" - }, - "bin": { - "tsx": "dist/cli.mjs" - }, - "engines": { - "node": ">=18.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - } - }, - "node_modules/tsx/node_modules/@esbuild/aix-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz", - "integrity": "sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/tsx/node_modules/@esbuild/android-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.2.tgz", - "integrity": "sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/tsx/node_modules/@esbuild/android-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz", - "integrity": "sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/tsx/node_modules/@esbuild/android-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.2.tgz", - "integrity": "sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz", - "integrity": "sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/tsx/node_modules/@esbuild/darwin-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz", - "integrity": "sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz", - "integrity": "sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz", - "integrity": "sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-arm": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz", - "integrity": "sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz", - "integrity": "sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz", - "integrity": "sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-loong64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz", - "integrity": "sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz", - "integrity": "sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==", - "cpu": [ - "mips64el" - ], + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", "dev": true, - "optional": true, - "os": [ - "linux" - ], + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, "engines": { - "node": ">=12" + "node": ">=16 || 14 >=14.17" } }, - "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz", - "integrity": "sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==", - "cpu": [ - "ppc64" - ], + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, - "optional": true, - "os": [ - "linux" - ], + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, "engines": { - "node": ">=12" + "node": ">=8" } }, - "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz", - "integrity": "sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==", - "cpu": [ - "riscv64" - ], + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" } }, - "node_modules/tsx/node_modules/@esbuild/linux-s390x": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz", - "integrity": "sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==", - "cpu": [ - "s390x" - ], + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", "dev": true, - "optional": true, - "os": [ - "linux" - ], + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, "engines": { - "node": ">=12" + "node": ">=0.8" } }, - "node_modules/tsx/node_modules/@esbuild/linux-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz", - "integrity": "sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==", - "cpu": [ - "x64" - ], + "node_modules/tinybench": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-4.0.1.tgz", + "integrity": "sha512-Nb1srn7dvzkVx0J5h1vq8f48e3TIcbrS7e/UfAI/cDSef/n8yLh4zsAEsFkfpw6auTY+ZaspEvam/xs8nMnotQ==", "dev": true, - "optional": true, - "os": [ - "linux" - ], + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=18.0.0" } }, - "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz", - "integrity": "sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==", - "cpu": [ - "x64" - ], + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", "dev": true, - "optional": true, - "os": [ - "netbsd" - ], + "license": "MIT" + }, + "node_modules/tinyglobby": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, "engines": { - "node": ">=12" + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz", - "integrity": "sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==", - "cpu": [ - "x64" - ], + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, - "optional": true, - "os": [ - "openbsd" - ], + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, "engines": { - "node": ">=12" + "node": ">=8.0" } }, - "node_modules/tsx/node_modules/@esbuild/sunos-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz", - "integrity": "sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==", - "cpu": [ - "x64" - ], + "node_modules/tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" + "license": "MIT", + "dependencies": { + "punycode": "^2.1.0" } }, - "node_modules/tsx/node_modules/@esbuild/win32-arm64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz", - "integrity": "sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==", - "cpu": [ - "arm64" - ], + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" + "license": "MIT", + "bin": { + "tree-kill": "cli.js" } }, - "node_modules/tsx/node_modules/@esbuild/win32-ia32": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz", - "integrity": "sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==", - "cpu": [ - "ia32" - ], + "node_modules/ts-api-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", "dev": true, - "optional": true, - "os": [ - "win32" - ], + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" } }, - "node_modules/tsx/node_modules/@esbuild/win32-x64": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz", - "integrity": "sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==", - "cpu": [ - "x64" - ], + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" + "license": "Apache-2.0" + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } } }, - "node_modules/tsx/node_modules/esbuild": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.2.tgz", - "integrity": "sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==", + "node_modules/tsup": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/tsup/-/tsup-8.5.0.tgz", + "integrity": "sha512-VmBp77lWNQq6PfuMqCHD3xWl22vEoWsKajkF8t+yMBawlUS8JzEI+vOVMeuNZIuMML8qXRizFKi9oD5glKQVcQ==", "dev": true, - "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "bundle-require": "^5.1.0", + "cac": "^6.7.14", + "chokidar": "^4.0.3", + "consola": "^3.4.0", + "debug": "^4.4.0", + "esbuild": "^0.25.0", + "fix-dts-default-cjs-exports": "^1.0.0", + "joycon": "^3.1.1", + "picocolors": "^1.1.1", + "postcss-load-config": "^6.0.1", + "resolve-from": "^5.0.0", + "rollup": "^4.34.8", + "source-map": "0.8.0-beta.0", + "sucrase": "^3.35.0", + "tinyexec": "^0.3.2", + "tinyglobby": "^0.2.11", + "tree-kill": "^1.2.2" + }, "bin": { - "esbuild": "bin/esbuild" + "tsup": "dist/cli-default.js", + "tsup-node": "dist/cli-node.js" }, "engines": { - "node": ">=12" + "node": ">=18" }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.20.2", - "@esbuild/android-arm": "0.20.2", - "@esbuild/android-arm64": "0.20.2", - "@esbuild/android-x64": "0.20.2", - "@esbuild/darwin-arm64": "0.20.2", - "@esbuild/darwin-x64": "0.20.2", - "@esbuild/freebsd-arm64": "0.20.2", - "@esbuild/freebsd-x64": "0.20.2", - "@esbuild/linux-arm": "0.20.2", - "@esbuild/linux-arm64": "0.20.2", - "@esbuild/linux-ia32": "0.20.2", - "@esbuild/linux-loong64": "0.20.2", - "@esbuild/linux-mips64el": "0.20.2", - "@esbuild/linux-ppc64": "0.20.2", - "@esbuild/linux-riscv64": "0.20.2", - "@esbuild/linux-s390x": "0.20.2", - "@esbuild/linux-x64": "0.20.2", - "@esbuild/netbsd-x64": "0.20.2", - "@esbuild/openbsd-x64": "0.20.2", - "@esbuild/sunos-x64": "0.20.2", - "@esbuild/win32-arm64": "0.20.2", - "@esbuild/win32-ia32": "0.20.2", - "@esbuild/win32-x64": "0.20.2" + "peerDependencies": { + "@microsoft/api-extractor": "^7.36.0", + "@swc/core": "^1", + "postcss": "^8.4.12", + "typescript": ">=4.5.0" + }, + "peerDependenciesMeta": { + "@microsoft/api-extractor": { + "optional": true + }, + "@swc/core": { + "optional": true + }, + "postcss": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/tsup/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" } }, "node_modules/type-check": { @@ -2681,6 +3488,7 @@ "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, + "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" }, @@ -2688,23 +3496,12 @@ "node": ">= 0.8.0" } }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/typescript": { - "version": "5.4.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", - "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "dev": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -2714,51 +3511,84 @@ } }, "node_modules/typescript-eslint": { - "version": "7.10.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.10.0.tgz", - "integrity": "sha512-thO8nyqptXdfWHQrMJJiJyftpW8aLmwRNs11xA8pSrXneoclFPstQZqXvDWuH1WNL4CHffqHvYUeCHTit6yfhQ==", + "version": "8.36.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.36.0.tgz", + "integrity": "sha512-fTCqxthY+h9QbEgSIBfL9iV6CvKDFuoxg6bHPNpJ9HIUzS+jy2lCEyCmGyZRWEBSaykqcDPf1SJ+BfCI8DRopA==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "7.10.0", - "@typescript-eslint/parser": "7.10.0", - "@typescript-eslint/utils": "7.10.0" + "@typescript-eslint/eslint-plugin": "8.36.0", + "@typescript-eslint/parser": "8.36.0", + "@typescript-eslint/utils": "8.36.0" }, "engines": { - "node": "^18.18.0 || >=20.0.0" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" } }, + "node_modules/ufo": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz", + "integrity": "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==", + "dev": true, + "license": "MIT" + }, "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz", + "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==", + "dev": true, + "license": "MIT" }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, + "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, + "node_modules/webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, + "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, @@ -2774,6 +3604,7 @@ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -2783,6 +3614,7 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -2801,6 +3633,7 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -2813,17 +3646,29 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/wrap-ansi-cjs/node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -2833,16 +3678,17 @@ "node": ">=8" } }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, - "engines": { - "node": ">=12" + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "engines": { + "node": ">=8" } }, "node_modules/wrap-ansi/node_modules/ansi-styles": { @@ -2850,6 +3696,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -2857,32 +3704,22 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, + "license": "MIT", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "node": ">=6" } }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true - }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" }, diff --git a/src/main/nodejs/havelessbemore/package.json b/src/main/nodejs/havelessbemore/package.json index 48c845f..c932aec 100644 --- a/src/main/nodejs/havelessbemore/package.json +++ b/src/main/nodejs/havelessbemore/package.json @@ -1,42 +1,48 @@ { - "$schema": "http://json.schemastore.org/package", + "$schema": "http://json.schemastore.org/package.json", + "name": "1brc-nodejs", + "version": "1.0.0", "description": "Submission for the One Billion Row Challenge", "license": "MIT", - "author": "Michael Rojas (https://github.com/havelessbemore)", + "type": "module", + "sideEffects": false, "homepage": "https://github.com/havelessbemore/1brc-nodejs", "bugs": "https://github.com/havelessbemore/1brc-nodejs/issues", - "sideEffects": false, + "author": { + "name": "Michael Rojas", + "url": "https://github.com/havelessbemore" + }, "engines": { - "node": ">= 18" + "node": ">=18" }, - "type": "module", - "main": "./dist/index.cjs", - "module": "./dist/index.mjs", - "types": "./dist/index.d.ts", "exports": { ".": { - "import": "./dist/index.mjs", - "require": "./dist/index.cjs", - "types": "./dist/index.d.ts" + "types": "./dist/esm/index.d.ts", + "require": "./dist/cjs/index.cjs", + "import": "./dist/esm/index.js" } }, "scripts": { - "bench": "tsx ./benchmarks/bench.ts ../../../../measurements.txt", - "build": "rimraf dist && tsc && node ./esbuild.config.js", - "format": "prettier . --write", - "lint": "eslint ." + "bench": "node --enable-source-maps dist/cjs/benchmarks/index.cjs ../../../../measurements.txt", + "build": "tsup", + "format": "prettier --write .", + "lint": "eslint .", + "start": "time node --enable-source-maps dist/cjs/index.cjs ../../../../measurements.txt" }, "devDependencies": { - "@types/node": "^20.10.6", - "esbuild": "^0.21.4", - "eslint": "^8.57.0", - "eslint-config-prettier": "^9.1.0", - "prettier": "^3.2.5", - "rimraf": "^5.0.7", - "tinybench": "^2.8.0", - "tslib": "^2.6.2", - "tsx": "^4.10.5", - "typescript": "^5.4.5", - "typescript-eslint": "^7.10.0" + "@eslint/js": "^9.26.0", + "@eslint/json": "^0.12.0", + "@types/node": "^24.0.11", + "esbuild": "^0.25.4", + "eslint": "^9.26.0", + "eslint-config-prettier": "^10.1.5", + "globals": "^16.1.0", + "husky": "^9.1.7", + "prettier": "^3.5.3", + "tinybench": "^4.0.1", + "ts-node": "^10.9.2", + "tsup": "^8.5.0", + "typescript": "^5.8.3", + "typescript-eslint": "^8.32.1" } } diff --git a/src/main/nodejs/havelessbemore/src/benchmarks/index.ts b/src/main/nodejs/havelessbemore/src/benchmarks/index.ts new file mode 100644 index 0000000..9ccd843 --- /dev/null +++ b/src/main/nodejs/havelessbemore/src/benchmarks/index.ts @@ -0,0 +1,72 @@ +import fs from "node:fs"; +import os from "node:os"; +import path from "node:path"; +import process from "node:process"; + +import { Bench, Task } from "tinybench"; + +import { run } from "../main"; + +// INPUT +const filePath = process.argv[2]; +const maxWorkers = os.availableParallelism(); +const workerPath = path.resolve(__filename, "../../index.cjs"); + +// OUTPUT +const dir = fs.mkdtempSync(path.join(os.tmpdir(), "1brc-")); + +main(); +async function main(): Promise { + // BENCHMARK + let i = 0; + let t0 = 0; + const bench = new Bench({ iterations: 5, warmupIterations: 3 }); + bench.add( + `1BRC`, + async () => { + const outPath = path.join(dir, `out_${i}.txt`); + return run(filePath, workerPath, maxWorkers, outPath); + }, + { + beforeAll: () => { + if (i == 0) { + t0 = performance.now(); + } + }, + beforeEach: async function (): Promise { + if (i > 0) { + console.log("Waiting 5 seconds..."); + await new Promise(resolve => setTimeout(resolve, 5000)); + } + const elapsed = toSeconds(performance.now() - t0); + console.log(`${this.name} (${elapsed}s): Running iteration ${++i}...`); + } + }, + ); + + // Run + await bench.run(); + + // Output + console.table(bench.tasks.map((task) => toRecord(task))); + const time = bench.tasks.reduce((sum, t) => sum + t.result!.totalTime, 0); + process.stdout.write(`Total time: ${toSeconds(time)}s\n`); + + // Cleanup + fs.rmSync(dir, { recursive: true, force: true }); +} + +// REPORTING +function toRecord(task: Task): Record { + const out: Record = {}; + out.Name = task.name; + out["Min (s)"] = toSeconds(task.result?.latency.min); + out["Max (s)"] = toSeconds(task.result?.latency.max); + out["Avg (s)"] = toSeconds(task.result?.latency.mean); + out.Samples = +(task.result?.latency.samples ?? []).length; + return out; +} + +function toSeconds(ms: number | undefined): number { + return Math.floor(ms ?? 0) / 1000; +} diff --git a/src/main/nodejs/havelessbemore/src/index.ts b/src/main/nodejs/havelessbemore/src/index.ts index 47891ad..f2933a2 100644 --- a/src/main/nodejs/havelessbemore/src/index.ts +++ b/src/main/nodejs/havelessbemore/src/index.ts @@ -1,5 +1,4 @@ import { availableParallelism } from "node:os"; -import { fileURLToPath } from "node:url"; import { isMainThread, parentPort } from "node:worker_threads"; import type { MergeRequest } from "./types/mergeRequest"; @@ -10,8 +9,7 @@ import { run as runMain } from "./main"; import { merge, run as runWorker } from "./worker"; if (isMainThread) { - const workerPath = fileURLToPath(import.meta.url); - runMain(process.argv[2], workerPath, availableParallelism()); + runMain(process.argv[2], __filename, availableParallelism()); } else { parentPort!.addListener("message", (msg: Request) => { if (msg.type === RequestType.PROCESS) { diff --git a/src/main/nodejs/havelessbemore/src/main.ts b/src/main/nodejs/havelessbemore/src/main.ts index a7359dc..bcf703e 100644 --- a/src/main/nodejs/havelessbemore/src/main.ts +++ b/src/main/nodejs/havelessbemore/src/main.ts @@ -1,20 +1,16 @@ -import { - closeSync, - createWriteStream, - fstatSync, - openSync, - WriteStream, -} from "node:fs"; -import { stdout } from "node:process"; +import fs from "node:fs"; +import process from "node:process"; -import type { MergeRequest } from "./types/mergeRequest"; -import type { MergeResponse } from "./types/mergeResponse"; -import type { ProcessRequest } from "./types/processRequest"; -import type { ProcessResponse } from "./types/processResponse"; +import { + MergeRequest, + MergeResponse, + ProcessRequest, + ProcessResponse, + RequestType, +} from "./types"; import { BRC } from "./constants/brc"; import { Config } from "./constants/config"; -import { RequestType } from "./types/request"; import { clamp, getChunkSize, getPageSize } from "./utils/stream"; import { print } from "./utils/utf8Trie"; import { createWorker, exec } from "./utils/worker"; @@ -29,10 +25,10 @@ export async function run( maxWorkers = clamp(maxWorkers, Config.WORKERS_MIN, Config.WORKERS_MAX); // Open the given file - const fd = openSync(filePath, "r"); + const fd = fs.openSync(filePath, "r"); // Get file stats - const fstats = fstatSync(fd); + const fstats = fs.fstatSync(fd); const fileSize = fstats.size; const pageSize = getPageSize(fileSize, maxWorkers); const chunkSize = getChunkSize(pageSize); @@ -100,11 +96,11 @@ export async function run( await Promise.all(tasks); // Close the file - closeSync(fd); + fs.closeSync(fd); // Print results - const out = createWriteStream(outPath, { - fd: outPath.length < 1 ? stdout.fd : undefined, + const out = fs.createWriteStream(outPath, { + fd: outPath.length < 1 ? process.stdout.fd : undefined, flags: "a", highWaterMark: Config.HIGH_WATER_MARK_OUT, }); @@ -114,7 +110,7 @@ export async function run( out.end("}\n"); function printStation( - stream: WriteStream, + stream: fs.WriteStream, name: Buffer, nameLen: number, vi: number, diff --git a/src/main/nodejs/havelessbemore/src/types/index.ts b/src/main/nodejs/havelessbemore/src/types/index.ts new file mode 100644 index 0000000..d278062 --- /dev/null +++ b/src/main/nodejs/havelessbemore/src/types/index.ts @@ -0,0 +1,6 @@ +export type { MergeRequest } from "./mergeRequest"; +export type { MergeResponse } from "./mergeResponse"; +export type { ProcessRequest } from "./processRequest"; +export type { ProcessResponse } from "./processResponse"; +export { type Request, RequestType } from "./request"; +export type { Response } from "./response"; diff --git a/src/main/nodejs/havelessbemore/src/types/response.ts b/src/main/nodejs/havelessbemore/src/types/response.ts index 8cd8ada..64b0c4c 100644 --- a/src/main/nodejs/havelessbemore/src/types/response.ts +++ b/src/main/nodejs/havelessbemore/src/types/response.ts @@ -1,2 +1,2 @@ -// eslint-disable-next-line @typescript-eslint/no-empty-interface +// eslint-disable-next-line @typescript-eslint/no-empty-object-type export interface Response {} diff --git a/src/main/nodejs/havelessbemore/src/worker.ts b/src/main/nodejs/havelessbemore/src/worker.ts index 733d3f0..854e4e9 100644 --- a/src/main/nodejs/havelessbemore/src/worker.ts +++ b/src/main/nodejs/havelessbemore/src/worker.ts @@ -1,4 +1,4 @@ -import { readSync } from "fs"; +import { readSync } from "node:fs"; import type { MergeRequest } from "./types/mergeRequest"; import type { MergeResponse } from "./types/mergeResponse"; @@ -47,7 +47,6 @@ export function run({ let trie = createTrie(id); // For each page - // eslint-disable-next-line no-constant-condition while (true) { // Get page start let start = pageSize * Atomics.add(page, 0, 1); diff --git a/src/main/nodejs/havelessbemore/tsconfig.json b/src/main/nodejs/havelessbemore/tsconfig.json index c9162b4..128f864 100644 --- a/src/main/nodejs/havelessbemore/tsconfig.json +++ b/src/main/nodejs/havelessbemore/tsconfig.json @@ -1,10 +1,10 @@ { - "$schema": "http://json.schemastore.org/tsconfig", + "$schema": "https://json.schemastore.org/tsconfig", "compilerOptions": { /* Visit https://aka.ms/tsconfig to read more about this file */ /* Projects */ - // "incremental": true /* Save .tsbuildinfo files to allow for incremental compilation of projects. */, + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ @@ -12,11 +12,13 @@ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ /* Language and Environment */ - "target": "ESNext" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + "target": "ES2020" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, "lib": [ - "ESNext" + "DOM", + "ES2020" ] /* Specify a set of bundled library declaration files that describe the target runtime environment. */, // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "libReplacement": true, /* Enable lib replacement. */ // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ @@ -28,23 +30,25 @@ // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ /* Modules */ - "module": "ESNext" /* Specify what module code is generated. */, - "rootDir": "." /* Specify the root folder within your source files. */, - "moduleResolution": "Bundler" /* Specify how TypeScript looks up a file from a given module specifier. */, + "module": "esnext" /* Specify what module code is generated. */, + // "rootDir": "./", /* Specify the root folder within your source files. */ + "moduleResolution": "bundler" /* Specify how TypeScript looks up a file from a given module specifier. */, // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ - // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + "paths": { + "src/*": ["./src/*"] + } /* Specify a set of entries that re-map imports to additional lookup locations. */, // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ - "types": [ - "node" - ] /* Specify type package names to be included without being referenced in a source file. */, + // "types": [] /* Specify type package names to be included without being referenced in a source file. */, // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ - // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ + // "rewriteRelativeImportExtensions": true, /* Rewrite '.ts', '.tsx', '.mts', and '.cts' file extensions in relative import paths to their JavaScript equivalent in output files. */ + // "resolvePackageJsonExports": true /* Use the package.json 'exports' field when resolving package imports. */, // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ - // "resolveJsonModule": true, /* Enable importing .json files. */ + // "noUncheckedSideEffectImports": true, /* Check side effect imports. */ + "resolveJsonModule": true /* Enable importing .json files. */, // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ @@ -54,17 +58,16 @@ // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ /* Emit */ - // "declaration": true /* Generate .d.ts files from TypeScript and JavaScript files in your project. */, - // "declarationMap": true, /* Create sourcemaps for d.ts files. */ - // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ - // "sourceMap": true /* Create source map files for emitted JavaScript files. */, + "declaration": true /* Generate .d.ts files from TypeScript and JavaScript files in your project. */, + "declarationMap": true /* Create sourcemaps for d.ts files. */, + "emitDeclarationOnly": true /* Only output d.ts files and not JavaScript files. */, + "sourceMap": true /* Create source map files for emitted JavaScript files. */, // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ "outDir": "./dist" /* Specify an output folder for all emitted files. */, // "removeComments": true, /* Disable emitting comments. */ - "noEmit": true /* Disable emitting files from a compilation. */, // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ - // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ @@ -76,11 +79,12 @@ // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ - // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ /* Interop Constraints */ - // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ - // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ + "isolatedModules": true /* Ensure that each file can be safely transpiled without relying on other imports. */, + // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ + // "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */ + // "erasableSyntaxOnly": true, /* Do not allow runtime constructs that are not part of ECMAScript. */ // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ @@ -89,18 +93,19 @@ /* Type Checking */ "strict": true /* Enable all strict type-checking options. */, "noImplicitAny": true /* Enable error reporting for expressions and declarations with an implied 'any' type. */, - // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + "strictNullChecks": true /* When type checking, take into account 'null' and 'undefined'. */, "strictFunctionTypes": true /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */, - // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ - // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ - // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + "strictBindCallApply": true /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */, + "strictPropertyInitialization": true /* Check for class properties that are declared but not set in the constructor. */, + // "strictBuiltinIteratorReturn": true, /* Built-in iterators are instantiated with a 'TReturn' type of 'undefined' instead of 'any'. */ + "noImplicitThis": true /* Enable error reporting when 'this' is given the type 'any'. */, // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ - // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + "alwaysStrict": true /* Ensure 'use strict' is always emitted. */, "noUnusedLocals": true /* Enable error reporting when local variables aren't read. */, "noUnusedParameters": true /* Raise an error when a function parameter isn't read. */, - // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "exactOptionalPropertyTypes": true /* Interpret optional property types as written, rather than adding 'undefined'. */, "noImplicitReturns": true /* Enable error reporting for codepaths that do not explicitly return in a function. */, - // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + "noFallthroughCasesInSwitch": true /* Enable error reporting for fallthrough cases in switch statements. */, // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ @@ -110,6 +115,5 @@ /* Completeness */ // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ "skipLibCheck": true /* Skip type checking all .d.ts files. */ - }, - "include": ["benchmarks", "src", "./*.config.ts"] + } } diff --git a/src/main/nodejs/havelessbemore/tsup.config.ts b/src/main/nodejs/havelessbemore/tsup.config.ts new file mode 100644 index 0000000..0d63a28 --- /dev/null +++ b/src/main/nodejs/havelessbemore/tsup.config.ts @@ -0,0 +1,34 @@ +import { defineConfig, type Options } from "tsup"; + +import pkg from "./package.json"; + +const bannerText = `/*! @license ${pkg.name} | ${pkg.license} | ${pkg.homepage} */`; + +const baseConfig: Options = { + banner: { js: bannerText }, + bundle: true, + clean: true, + dts: true, + entryPoints: ["src/index.ts", "src/benchmarks/index.ts"], + minify: true, + sourcemap: true, + splitting: false, + platform: "neutral", +}; + +const cjsConfig: Options = { + name: "CommonJS", + format: "cjs", + outDir: "dist/cjs", +}; + +const esmConfig: Options = { + name: "ECMAScript", + format: "esm", + outDir: "dist/esm", +}; + +export default defineConfig([ + { ...baseConfig, ...cjsConfig }, + { ...baseConfig, ...esmConfig }, +]);