@hugoalh/djb2a
Version:
A CLI and module to get the non-cryptographic hash of the data with algorithm DJB2a.
130 lines (129 loc) • 3.49 kB
JavaScript
import "./_dnt.polyfills.js";
/**
* Get the non-cryptographic hash of the data with algorithm DJB2a (32 bits).
*/
export class DJB2a {
get [Symbol.toStringTag]() {
return "DJB2a";
}
#freezed = false;
#hash = null;
#bin = 5381n;
/**
* Initialize.
* @param {DJB2aAcceptDataType} [data] Data. Can append later via the method {@linkcode DJB2a.update}.
*/
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 update.
* @returns {this}
*/
freeze() {
this.#freezed = true;
return this;
}
/**
* Get the non-cryptographic hash of the data, in original format.
* @returns {bigint}
*/
hash() {
if (this.#hash === null) {
this.#hash = BigInt.asUintN(32, this.#bin);
}
return this.#hash;
}
/**
* Get the non-cryptographic hash of the data, in Base16.
* @returns {string}
*/
hashBase16() {
return this.hashBigInt().toString(16).toUpperCase();
}
/**
* Get the non-cryptographic hash of the data, in Base32Hex ({@link https://datatracker.ietf.org/doc/html/rfc4648#section-7 RFC 4648 §7}).
* @returns {string}
*/
hashBase32Hex() {
return this.hashBigInt().toString(32).toUpperCase();
}
/**
* Get the non-cryptographic hash of the data, in Base36.
* @returns {string}
*/
hashBase36() {
return this.hashBigInt().toString(36).toUpperCase();
}
/**
* Get the non-cryptographic hash of the data, in big integer.
* @returns {bigint}
*/
hashBigInt() {
return this.hash();
}
/**
* Get the non-cryptographic hash of the data, in big integer.
* @returns {bigint}
*/
hashBigInteger = this.hashBigInt;
/**
* Get the non-cryptographic hash of the data, in hex/hexadecimal without padding.
* @returns {string}
*/
hashHex() {
return this.hashBase16();
}
/**
* Get the non-cryptographic hash of the data, in hex/hexadecimal with padding.
* @returns {string}
*/
hashHexPadding() {
return this.hashHex().padStart(8, "0");
}
/**
* Get the non-cryptographic hash of the data, in number.
* @returns {number}
*/
hashNumber() {
return Number(this.hash());
}
/**
* Append data.
* @param {DJB2aAcceptDataType} data Data.
* @returns {this}
*/
update(data) {
if (this.#freezed) {
throw new Error(`Instance is freezed!`);
}
this.#hash = null;
const raw = (typeof data === "string") ? data : new TextDecoder().decode(data);
for (let index = 0; index < raw.length; index += 1) {
this.#bin = this.#bin * 33n ^ BigInt(raw.charCodeAt(index));
}
return this;
}
/**
* Initialize from the readable stream, asynchronously.
* @param {ReadableStream<DJB2aAcceptDataType>} stream Readable stream.
* @returns {Promise<DJB2a>}
*/
static async fromStream(stream) {
const instance = new this();
for await (const chunk of stream) {
instance.update(chunk);
}
return instance;
}
}
export default DJB2a;