UNPKG

@hugoalh/sdbm

Version:

A module to get the non-cryptographic hash of the data with algorithm SDBM.

93 lines (92 loc) 2.78 kB
import "./_dnt.polyfills.js"; if (typeof Uint8Array.fromHex === "undefined") { //deno-lint-ignore hugoalh/no-import-dynamic -- Polyfill. await import("es-arraybuffer-base64/Uint8Array.fromHex/auto"); } /** * Get the non-cryptographic hash of the data with algorithm SDBM (32 bits). */ export class SDBM { get [Symbol.toStringTag]() { return "SDBM"; } #freezed = false; #hashHex = null; #hashUint8Array = null; #bin = 0n; /** * Initialize. * @param {SDBMAcceptDataType} [data] Data. Can append later via the method {@linkcode SDBM.update} and {@linkcode SDBM.updateFromStream}. */ constructor(data) { if (typeof data !== "undefined") { this.update(data); } } /** * Whether the instance is freezed. * @returns {boolean} */ get freezed() { return this.#freezed; } /** * Freeze the instance to prevent any further update. * @returns {this} */ freeze() { this.#freezed = true; return this; } /** * Get the non-cryptographic hash of the data, in Uint8Array. * @returns {Uint8Array} */ hash() { this.#hashUint8Array ??= Uint8Array.fromHex(this.hashHex()); return Uint8Array.from(this.#hashUint8Array); } /** * Get the non-cryptographic hash of the data, in hexadecimal with padding. * @returns {string} */ hashHex() { if (this.#hashHex === null) { const result = BigInt.asUintN(32, this.#bin).toString(16).toUpperCase().padStart(8, "0"); if (result.length !== 8) { throw new Error(`Unexpected hash hex result \`${result}\`! Please submit a bug report.`); } this.#hashHex = result; } return this.#hashHex; } /** * Append data. * @param {SDBMAcceptDataType} data Data. * @returns {this} */ update(data) { if (this.#freezed) { throw new Error(`Instance is freezed!`); } this.#hashHex = null; this.#hashUint8Array = null; const dataFmt = (typeof data === "string") ? data : new TextDecoder().decode(data); for (let index = 0; index < dataFmt.length; index += 1) { this.#bin = BigInt(dataFmt.charCodeAt(index)) + (this.#bin << 6n) + (this.#bin << 16n) - this.#bin; } return this; } /** * Append data from the readable stream. * @param {ReadableStream<SDBMAcceptDataType>} stream Data from the readable stream. * @returns {Promise<this>} */ async updateFromStream(stream) { for await (const chunk of stream) { this.update(chunk); } return this; } } export default SDBM;