UNPKG

@rimbu/hashed

Version:

Immutable HashMap and HashSet implementations for TypeScript

268 lines (267 loc) 9.81 kB
import { type StreamSource } from '@rimbu/stream'; /** * Interface used to hash objects for hashed collections. * @typeparam UK - the upper type limit for which the hasher is assumed to be valid * @note A hashcode is a 32-bit JS integer and therefore signed. * You can obtain the 32-bit version of any JS number by applying a * bitwise operator to it, e.g. if x is a number, use x | 0. */ export interface Hasher<UK> { /** * Returns true if this hasher can be applied to the given `obj` object. * @param obj - the object to check * @example * ```ts * const h = Hasher.numberHasher() * console.log(h.isValid(5)) * // => true * console.log(h.isValid('a')) * // => false * ``` */ isValid(obj: unknown): obj is UK; /** * Returns the 32-bit hash code for the given `value`. * @param value - the value to hash * @note it is assumed that the caller has verified that the given object * is valid, either by knowing the types up front, or by using the `isValid` function. * @example * ```ts * const h = Hasher.anyHasher() * h.hash([1, 3, 2]) * ``` */ hash(value: UK): number; } export declare namespace Hasher { function defaultHasher(): Hasher<any>; /** * Returns a Hasher instance for string values. * @example * ```ts * const h = Hasher.stringHasher() * h.hash('abc') * ``` */ function stringHasher(): Hasher<string>; /** * Returns a Hasher instance that hashes the string representation of any value * @param maxStepBits - the maximum amount of samples to take from the string * @example * ```ts * const h = Hasher.anyToStringHasher() * h.hash([1, 3, 'a']) * ``` */ function anyToStringHasher(maxStepBits?: number): Hasher<any>; /** * Returns a Hasher instance that hashes any value by hashing the string resulting from * applying JSON.stringify to the value. * @example * ```ts * const h = Hasher.anyJsonStringHasher() * console.log(h.hash({ a: 1, b: 2 }) === h.hash({ b: 2, a: 1 })) * // => false * ``` */ function anyJsonStringHasher(): Hasher<any>; function stringCaseInsensitiveHasher(): Hasher<string>; /** * Returns a Hasher that hashes arrays of elements by sampling the array and using * the given `itemHasher` to hash the sampled elements. * @typeparam T - the array element type * @param options - (optional) an object containing the following items:<br/> * - itemHasher: (optional) a Hasher instance used to hash elements in the array<br/> * - maxStepBits: (optional) the amount of bits to determine the maximum amount of array * elements to process * @example * ```ts * const h = Hasher.arrayHasher() * console.log(h.hash([1, 2, 3] === h.hash([1, 3, 2]))) * // => false * ``` */ function arrayHasher<T = any>(options?: { itemHasher?: Hasher<T>; maxStepBits?: number; }): Hasher<readonly T[]>; /** * Returns a Hasher instance that hashes any StreamSource limited to a certain amount * of elements to prevent haning on infinite streams. * @typeparam T - the StreamSource element type * @param options - (optional) an object containing the following items:<br/> * - itemHasher: (optional) a Hasher instance used to hash elements in the array<br/> * - maxStepBits: (optional) the amount of bits to determine the maximum amount of array * elements to process * @example * ```ts * const h = Hasher.streamSourceHasher() * h.hash(Stream.random()) * // infinite stream but will not hang due to the max step limit * ``` */ function streamSourceHasher<T = any>(options?: { itemHasher?: Hasher<T>; maxStepBits?: number; }): Hasher<StreamSource<T>>; /** * Returns a Hasher instance that hashes numbers, including 'special' values like NaN and infinities. * @example * ```ts * const h = Hasher.numberHasher() * console.log(h.hash(Number.POSITIVE_INFINITY) === h.hash(Number.NEGATIVE_INFINITY)) * // => false * console.log(h.hash(Number.NaN) === h.hash(Number.NaN)) * // => true * ``` */ function numberHasher(): Hasher<number>; /** * Returns a Hasher instance that hashes booleans. * @example * ```ts * const h = Hasher.booleanHasher() * console.log(h.hash(true) === h.hash(false)) * // => false * ``` */ function booleanHasher(): Hasher<boolean>; /** * Returns a Hasher instance that hashes bigints. * @example * ```ts * const h = Hasher.bigintHasher() * console.log(h.hash(BigInt(5)) === h.hash(BigInt(10))) * // => false * ``` */ function bigintHasher(): Hasher<bigint>; /** * Returns a Hasher instance that hashes the `.valueOf` value of the given * object using the given `valueHasher` for instances of given `cls` class. * @typeparam T - the input object type * @typeparam V - the .valueOf property type * @param cls - the class containing the contructur to check for validity of a given object * @param valueHasher - the Hasher instance to use for the `.valueOf` values * @example * ```ts * const h = Hasher.createValueOfHasher(Date) * console.log(h.isValid(new Boolean(true))) * // => false * const d1 = new Date() * const d2 = new Date(d1) * console.log(h.hash(d1) === h.hash(d2)) * // => true * ``` */ function createValueOfHasher<T extends { valueOf(): V; }, V>(cls: { new (): T; }, valueHasher?: Hasher<V>): Hasher<T>; /** * Returns a Hasher instance that hashes Dates. * @example * ```ts * const h = Hasher.dateHasher() * const d1 = new Date() * const d2 = new Date(d1) * console.log(h.hash(d1) === h.hash(d2)) * // => true * ``` */ function dateHasher(): Hasher<Date>; /** * Returns a Hasher instance that hashes objects of key type K and value type V. * @typeparam K - the key type * @typeparam V - the value type * @param options - (optional) an object containing:<br/> * - keyHasher: (optional) a Hasher instance that is used to hash object keys<br/> * - valueHasher: (optional) a Hasher instance that is used to hash object values * @example * ```ts * const h = Hasher.objectHasher() * console.log(h.hash({ a: 1, b: 2 }) === h.hash({ b: 2, a: 1 })) * // => true * ``` */ function objectHasher<K extends string | number | symbol, V = any>(options?: { keyHasher: Hasher<K>; valueHasher: Hasher<V>; }): Hasher<Record<K, V>>; /** * Returns a Hasher instance that hashes objects of key type K and value type V. * If a value if an object or array, it will convert those values to a string. * @typeparam K - the key type * @typeparam V - the value type * @example * ```ts * const h = Hasher.objectShallowHasher() * console.log(h.hash({ a: 1, b: 2 }) === h.hash({ b: 2, a: 1 })) * // => true * ``` */ function objectShallowHasher<K extends string | number | symbol, V = any>(): Hasher<Record<K, V>>; /** * Returns a Hasher instance that hashes objects of key type K and value type V. * If a value if an object or array, it will recursively hash its values. * @note be careful with circular structures, they can cause an infinite loop * @typeparam K - the key type * @typeparam V - the value type * @example * ```ts * const h = Hasher.objectDeepHasher() * console.log(h.hash({ a: 1, b: 2 }) === h.hash({ b: 2, a: 1 })) * // => true * ``` */ function objectDeepHasher<K extends string | number | symbol, V = any>(): Hasher<Record<K, V>>; /** * Returns a Hasher instance that hashes any value, but never traverses into an object * or array to hash its elements. In those cases it will use toString. * @example * ```ts * const h = Hasher.anyFlatHasher() * console.log(h.hash({ a: 1, b: 2 }) === h.hash({ b: 2, a: 1 })) * // => false * ``` */ function anyFlatHasher(): Hasher<any>; /** * Returns a Hasher instance that hashes any value, but only traverses into an object * or array to hash its elements one level deep. After one level, it will use toString. * @example * ```ts * const h = Hasher.anyShallowHasher() * console.log(h.hash({ a: 1, b: 2 }) === h.hash({ b: 2, a: 1 })) * // => true * console.log(h.hash([{ a: 1, b: 2 }]) === h.hash([{ b: 2, a: 1 }])) * // => false * ``` */ function anyShallowHasher(): Hasher<any>; /** * Returns a Hasher instance that hashes any value, and traverses into an object * or array to hash its elements. * @example * ```ts * const h = Hasher.anyDeepHasher() * console.log(h.hash({ a: 1, b: 2 }) === h.hash({ b: 2, a: 1 })) * // => true * console.log(h.hash([{ a: 1, b: 2 }]) === h.hash([{ b: 2, a: 1 }])) * // => true * ``` */ function anyDeepHasher(): Hasher<any>; /** * Returns a Hasher that will return equal hash values for values in a tuple regardless * of their order, and uses the given `hasher` function to hash the tuple elements. * @param hasher - the Hasher instance to use for tuple elements * @example * ```ts * const h = Hasher.tupleSymmetric() * console.log(h.hash(['abc', 'def']) === h.hash(['def', 'abc'])) * ``` */ function tupleSymmetric<T>(hasher?: Hasher<T>): Hasher<readonly [T, T]>; }