@hugoalh/sdbm
Version:
A module to get the non-cryptographic hash of the data with algorithm SDBM.
93 lines (92 loc) • 2.78 kB
JavaScript
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;