@rimbu/hashed
Version:
Immutable HashMap and HashSet implementations for TypeScript
268 lines (267 loc) • 9.81 kB
text/typescript
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]>;
}