{"version":3,"sources":["../src/bloomfilter.ts"],"names":["fileURLToPath","fs"],"mappings":"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","file":"index.cjs","sourcesContent":["import * as fs from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\n\n// type FastBloomFilter = {\n// \taddString(text: string): void; // Insert a UTF-8 string into the filter\n// \thasString(text: string): boolean; // Check a UTF-8 string\n// \tadd(buffer: Uint8Array): void; // Insert a raw byte buffer\n// \thas(buffer: Uint8Array): boolean; // Check a raw byte buffer\n// \tbitCount: number; // Total number of bits in the bit array\n// \thashCount: number; // Number of hash functions (k)\n// \tdispose(): void; // Free all WASM-allocated memory\n// };\n\n/**\n * WebAssembly-backed Bloom filter.\n *\n * Use `FastBloomFilter.create(bitCount, hashCount)` to asynchronously load the\n * WASM module, allocate the underlying bitset, and receive a runtime wrapper\n * with convenience methods (`addString`, `has`, etc.).\n *\n * Memory layout:\n * - A persistent bitset is allocated once via `malloc`, sized according to\n *   `bitCount` (rounded up to the next 32-bit boundary).\n * - A temporary input buffer (`bufferPtr`) is allocated and dynamically resized\n *   when strings or byte arrays are added / queried.\n *\n * HOW IT WORKS:\n * - Strings are UTF-8 encoded on the JS side and copied into WASM memory.\n *   The WASM function `bloom_add(...)` then reads the raw bytes, hashes them\n *   using `XXH3`, and sets multiple bits in the bitset.\n * - `has(...)` performs the same hashing logic and checks whether all probed\n *   bit positions are set.\n * - This is a **classic Bloom filter**: it offers *no false negatives* but may\n *   return *false positives* depending on `k` (hashCount) and bit density.\n *\n * Performance notes:\n * - Reuses a single scratch buffer to avoid allocating / freeing every call.\n *\n * Example usage:\n * ```ts\n * const filter = await FastBloomFilter.create(1_000_000, 7);\n * filter.addString(\"hello\");\n * console.log(filter.hasString(\"hello\")); // true\n * console.log(filter.hasString(\"world\")); // maybe false\n * filter.dispose();\n * ```\n */\nexport type BloomFilterExport = Uint8Array;\n\nexport default class FastBloomFilter {\n\tprivate static readonly _MAGIC: Uint8Array = new Uint8Array([\n\t\t0x46, 0x42, 0x46, 0x32,\n\t]); // \"FBF2\"\n\n\tprivate readonly _bitCount: number;\n\tprivate readonly _byteCount: number;\n\tprivate readonly _hashCount: number;\n\n\tprivate readonly _encoder: TextEncoder;\n\tprivate readonly _ex: WasmExports;\n\tprivate readonly _bitsetPtr: number;\n\tprivate _bufferPtr: number;\n\tprivate _bufferSize: number;\n\tprivate _bufferU8View: Uint8Array;\n\n\tpublic get bitCount(): number {\n\t\treturn this._bitCount;\n\t}\n\tpublic get hashCount(): number {\n\t\treturn this._hashCount;\n\t}\n\n\tprivate constructor(\n\t\tbitCount: number,\n\t\thashCount: number,\n\t\tex: WasmExports,\n\t\tdata?: Uint8Array,\n\t) {\n\t\t// round up to the next multiple of 32\n\t\tthis._bitCount = (bitCount + 31) & ~31;\n\t\tthis._byteCount = this._bitCount >>> 3;\n\t\tthis._bitsetPtr = ex.malloc(this._byteCount);\n\t\tif (data) {\n\t\t\tconst bitsetU8View = new Uint8Array(\n\t\t\t\tex.memory.buffer,\n\t\t\t\tthis._bitsetPtr,\n\t\t\t\tthis._byteCount,\n\t\t\t);\n\t\t\tbitsetU8View.set(data);\n\t\t}\n\n\t\tthis._hashCount = hashCount | 0;\n\t\tthis._encoder = new TextEncoder();\n\t\tthis._bufferPtr = 0;\n\t\tthis._bufferSize = 0;\n\t\tthis._bufferU8View = new Uint8Array(ex.memory.buffer, 0, 0);\n\n\t\tthis._ex = ex;\n\t}\n\n\t/**\n\t * Load the WASM module and return a ready-to-use Bloom filter.\n\t *\n\t * @param bitCount Desired number of bits. Rounded up to the nearest multiple of 32.\n\t * @param hashCount Number of hash rounds (k). More rounds reduce false positives.\n\t * @returns A promise that resolves to the created bloom filter.\n\t */\n\tstatic async create(\n\t\tbitCount: number,\n\t\thashCount: number,\n\t): Promise<FastBloomFilter> {\n\t\tif (bitCount <= 0) {\n\t\t\tthrow new Error(\"bitCount must be > 0\");\n\t\t}\n\t\tif (hashCount <= 0) {\n\t\t\tthrow new Error(\"hashCount must be > 0\");\n\t\t}\n\n\t\tconst ex = await FastBloomFilter.instantiateWasm();\n\t\treturn new FastBloomFilter(bitCount, hashCount, ex);\n\t}\n\n\t/**\n\t * Create a bloom filter with the optimal parameters for the given expected items and false positive rate.\n\t * @param expectedItems Expected number of items to be inserted into the bloom filter.\n\t * @param falsePositiveRate Desired false positive rate.\n\t * @returns A promise that resolves to the created bloom filter.\n\t */\n\tstatic async createOptimal(\n\t\texpectedItems: number,\n\t\tfalsePositiveRate: number,\n\t): Promise<FastBloomFilter> {\n\t\tif (expectedItems <= 0) {\n\t\t\tthrow new Error(\"expectedItems must be > 0\");\n\t\t}\n\t\tif (falsePositiveRate <= 0 || falsePositiveRate >= 1) {\n\t\t\tthrow new Error(\"falsePositiveRate must be between 0 and 1\");\n\t\t}\n\n\t\tconst ln2 = Math.log(2);\n\t\tconst bitCount = Math.ceil(\n\t\t\t(-expectedItems * Math.log(falsePositiveRate)) / (ln2 * ln2),\n\t\t);\n\t\tconst hashCount = Math.max(1, Math.round((bitCount / expectedItems) * ln2));\n\n\t\treturn FastBloomFilter.create(bitCount, hashCount);\n\t}\n\n\tprivate static async instantiateWasm(): Promise<WasmExports> {\n\t\tconst wasmUrl = new URL(\"./wasm/bloomfilter.wasm\", import.meta.url);\n\t\tconst wasmPath = fileURLToPath(wasmUrl);\n\t\tconst wasmBuffer = fs.readFileSync(wasmPath);\n\t\tconst { instance } = await WebAssembly.instantiate(wasmBuffer);\n\t\treturn instance.exports as unknown as WasmExports;\n\t}\n\n\t// Ensure the temp input buffer is large enough; if not, free and reallocate\n\tensureCapacity(utf8Len: number) {\n\t\tif (utf8Len <= this._bufferSize) return;\n\t\tlet newSize = this._bufferSize ? this._bufferSize : 256;\n\t\twhile (newSize < utf8Len) newSize <<= 1;\n\t\tif (this._bufferPtr) this._ex.free(this._bufferPtr);\n\t\tthis._bufferPtr = this._ex.malloc(newSize);\n\t\tthis._bufferSize = newSize;\n\t\tthis._bufferU8View = new Uint8Array(\n\t\t\tthis._ex.memory.buffer,\n\t\t\tthis._bufferPtr,\n\t\t\tthis._bufferSize,\n\t\t);\n\t}\n\n\t// ---- String-based API ----\n\n\taddString(text: string) {\n\t\tthis.ensureCapacity(text.length << 2); // Overprovision worst-case UTF-8 expansion\n\t\tconst { written } = this._encoder.encodeInto(text, this._bufferU8View);\n\t\tthis._ex.bloom_add(\n\t\t\tthis._bufferPtr,\n\t\t\twritten,\n\t\t\tthis._hashCount,\n\t\t\tthis._bitCount,\n\t\t\tthis._bitsetPtr,\n\t\t);\n\t}\n\n\thasString(text: string): boolean {\n\t\tthis.ensureCapacity(text.length << 2);\n\t\tconst { written } = this._encoder.encodeInto(text, this._bufferU8View);\n\t\treturn (\n\t\t\tthis._ex.bloom_has(\n\t\t\t\tthis._bufferPtr,\n\t\t\t\twritten,\n\t\t\t\tthis._hashCount,\n\t\t\t\tthis._bitCount,\n\t\t\t\tthis._bitsetPtr,\n\t\t\t) === 1\n\t\t);\n\t}\n\n\t// ---- Raw buffer API ----\n\n\tadd(buffer: Uint8Array) {\n\t\tthis.ensureCapacity(buffer.length);\n\t\tthis._bufferU8View.set(buffer);\n\t\tthis._ex.bloom_add(\n\t\t\tthis._bufferPtr,\n\t\t\tbuffer.length,\n\t\t\tthis._hashCount,\n\t\t\tthis._bitCount,\n\t\t\tthis._bitsetPtr,\n\t\t);\n\t}\n\n\thas(buffer: Uint8Array): boolean {\n\t\tthis.ensureCapacity(buffer.length);\n\t\tthis._bufferU8View.set(buffer);\n\t\treturn (\n\t\t\tthis._ex.bloom_has(\n\t\t\t\tthis._bufferPtr,\n\t\t\t\tbuffer.length,\n\t\t\t\tthis._hashCount,\n\t\t\t\tthis._bitCount,\n\t\t\t\tthis._bitsetPtr,\n\t\t\t) === 1\n\t\t);\n\t}\n\n\texport(): Uint8Array {\n\t\tconst bitsetU8View = new Uint8Array(\n\t\t\tthis._ex.memory.buffer,\n\t\t\tthis._bitsetPtr,\n\t\t\tthis._byteCount,\n\t\t);\n\t\tconst headerLength = FastBloomFilter._MAGIC.length + 8;\n\t\tconst exportBuffer = new ArrayBuffer(headerLength + bitsetU8View.length);\n\t\tconst exportView8 = new Uint8Array(exportBuffer);\n\t\texportView8.set(FastBloomFilter._MAGIC, 0);\n\t\tconst headerView = new DataView(\n\t\t\texportBuffer,\n\t\t\tFastBloomFilter._MAGIC.length,\n\t\t\t8,\n\t\t);\n\t\theaderView.setUint32(0, this._bitCount, true);\n\t\theaderView.setUint32(4, this._hashCount, true);\n\t\texportView8.set(bitsetU8View, headerLength);\n\t\treturn exportView8;\n\t}\n\n\tstatic async import(\n\t\texportedBloomFilter: Uint8Array,\n\t): Promise<FastBloomFilter> {\n\t\tconst headerLength = FastBloomFilter._MAGIC.length + 8;\n\n\t\tconst { buffer, byteOffset, byteLength } = exportedBloomFilter;\n\t\tconst magicView = new Uint8Array(\n\t\t\tbuffer,\n\t\t\tbyteOffset,\n\t\t\tFastBloomFilter._MAGIC.length,\n\t\t);\n\t\tfor (let i = 0; i < FastBloomFilter._MAGIC.length; i += 1) {\n\t\t\tif (magicView[i] !== FastBloomFilter._MAGIC[i]) {\n\t\t\t\tthrow new Error(\"Invalid magic number\");\n\t\t\t}\n\t\t}\n\n\t\tconst headerView = new DataView(\n\t\t\tbuffer,\n\t\t\tbyteOffset + FastBloomFilter._MAGIC.length,\n\t\t\t8,\n\t\t);\n\t\tconst bitCount = headerView.getUint32(0, true);\n\t\tconst hashCount = headerView.getUint32(4, true);\n\n\t\tconst expectedByteCount = ((bitCount + 31) & ~31) >>> 3;\n\t\tconst payloadLength = byteLength - headerLength;\n\t\tif (payloadLength !== expectedByteCount) {\n\t\t\tthrow new Error(\"Bloom filter payload has unexpected length\");\n\t\t}\n\n\t\tconst data = new Uint8Array(\n\t\t\tbuffer,\n\t\t\tbyteOffset + headerLength,\n\t\t\tpayloadLength,\n\t\t);\n\t\tconst ex = await FastBloomFilter.instantiateWasm();\n\n\t\treturn new FastBloomFilter(bitCount, hashCount, ex, data);\n\t}\n\n\t// ---- Cleanup ----\n\n\tdispose() {\n\t\tif (this._bufferPtr) {\n\t\t\tthis._ex.free(this._bufferPtr);\n\t\t\tthis._bufferPtr = 0;\n\t\t\tthis._bufferSize = 0;\n\t\t}\n\t\tif (this._bitsetPtr) this._ex.free(this._bitsetPtr);\n\t}\n}\n\ntype WasmExports = {\n\tmemory: WebAssembly.Memory;\n\tmalloc: (size: number) => number;\n\tfree: (ptr: number) => void;\n\tbloom_add: (\n\t\tdataPtr: number,\n\t\tlen: number,\n\t\tk: number,\n\t\tbitCount: number,\n\t\tbitset32Ptr: number,\n\t) => void;\n\tbloom_has: (\n\t\tdataPtr: number,\n\t\tlen: number,\n\t\tk: number,\n\t\tbitCount: number,\n\t\tbitset32Ptr: number,\n\t) => number;\n};\n"]}