Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 35 additions & 15 deletions src/Hash.js → src/Hash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,16 @@ import { smi } from './Math';

const defaultValueOf = Object.prototype.valueOf;

export function hash(o) {
export function hash(o: unknown): number {
// eslint-disable-next-line eqeqeq
if (o == null) {
return hashNullish(o);
}

// @ts-expect-error don't care about object beeing typed as `{}` here
if (typeof o.hashCode === 'function') {
// Drop any high bits from accidentally long hash codes.
// @ts-expect-error don't care about object beeing typed as `{}` here
return smi(o.hashCode(o));
}

Expand Down Expand Up @@ -45,12 +47,12 @@ export function hash(o) {
}
}

function hashNullish(nullish) {
function hashNullish(nullish: null | undefined): number {
return nullish === null ? 0x42108422 : /* undefined */ 0x42108423;
}

// Compress arbitrarily large numbers into smi hashes.
function hashNumber(n) {
function hashNumber(n: number): number {
if (n !== n || n === Infinity) {
return 0;
}
Expand All @@ -65,7 +67,7 @@ function hashNumber(n) {
return smi(hash);
}

function cachedHashString(string) {
function cachedHashString(string: string): number {
let hashed = stringHashCache[string];
if (hashed === undefined) {
hashed = hashString(string);
Expand All @@ -80,7 +82,7 @@ function cachedHashString(string) {
}

// http://jsperf.com/hashing-strings
function hashString(string) {
function hashString(string: string): number {
// This is the hash from JVM
// The hash code for a string is computed as
// s[0] * 31 ^ (n - 1) + s[1] * 31 ^ (n - 2) + ... + s[n - 1],
Expand All @@ -94,7 +96,7 @@ function hashString(string) {
return smi(hashed);
}

function hashSymbol(sym) {
function hashSymbol(sym: symbol): number {
let hashed = symbolMap[sym];
if (hashed !== undefined) {
return hashed;
Expand All @@ -107,21 +109,25 @@ function hashSymbol(sym) {
return hashed;
}

function hashJSObj(obj) {
let hashed;
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
function hashJSObj(obj: object | Function): number {
let hashed: number | undefined;
if (usingWeakMap) {
// @ts-expect-error weakMap is defined
hashed = weakMap.get(obj);
if (hashed !== undefined) {
return hashed;
}
}

// @ts-expect-error used for old code, will be removed
hashed = obj[UID_HASH_KEY];
if (hashed !== undefined) {
return hashed;
}

if (!canDefineProperty) {
// @ts-expect-error used for old code, will be removed
hashed = obj.propertyIsEnumerable && obj.propertyIsEnumerable[UID_HASH_KEY];
if (hashed !== undefined) {
return hashed;
Expand All @@ -136,6 +142,7 @@ function hashJSObj(obj) {
hashed = nextHash();

if (usingWeakMap) {
// @ts-expect-error weakMap is defined
weakMap.set(obj, hashed);
} else if (isExtensible !== undefined && isExtensible(obj) === false) {
throw new Error('Non-extensible objects are not allowed as keys.');
Expand All @@ -157,15 +164,19 @@ function hashJSObj(obj) {
obj.propertyIsEnumerable = function () {
return this.constructor.prototype.propertyIsEnumerable.apply(
this,
// eslint-disable-next-line prefer-rest-params
arguments
);
};
// @ts-expect-error used for old code, will be removed
obj.propertyIsEnumerable[UID_HASH_KEY] = hashed;
// @ts-expect-error used for old code, will be removed
} else if (obj.nodeType !== undefined) {
// At this point we couldn't get the IE `uniqueID` to use as a hash
// and we couldn't use a non-enumerable property to exploit the
// dontEnum bug so we simply add the `UID_HASH_KEY` on the node
// itself.
// @ts-expect-error used for old code, will be removed
obj[UID_HASH_KEY] = hashed;
} else {
throw new Error('Unable to set a non-enumerable property on object.');
Expand All @@ -178,6 +189,7 @@ function hashJSObj(obj) {
const isExtensible = Object.isExtensible;

// True if Object.defineProperty works as expected. IE8 fails this test.
// TODO remove this as widely available https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
const canDefineProperty = (function () {
try {
Object.defineProperty({}, '@', {});
Expand All @@ -190,24 +202,30 @@ const canDefineProperty = (function () {

// IE has a `uniqueID` property on DOM nodes. We can construct the hash from it
// and avoid memory leaks from the IE cloneNode bug.
function getIENodeHash(node) {
// TODO remove this method as only used if `canDefineProperty` is false
function getIENodeHash(node: unknown): number | undefined {
// @ts-expect-error don't care
if (node && node.nodeType > 0) {
// @ts-expect-error don't care
switch (node.nodeType) {
case 1: // Element
// @ts-expect-error don't care
return node.uniqueID;
case 9: // Document
// @ts-expect-error don't care
return node.documentElement && node.documentElement.uniqueID;
}
}
}

function valueOf(obj) {
function valueOf(obj: object): unknown {
return obj.valueOf !== defaultValueOf && typeof obj.valueOf === 'function'
? obj.valueOf(obj)
? // @ts-expect-error weird the "obj" parameter as `valueOf` should not have a parameter
obj.valueOf(obj)
: obj;
}

function nextHash() {
function nextHash(): number {
const nextHash = ++_objHashUID;
if (_objHashUID & 0x40000000) {
_objHashUID = 0;
Expand All @@ -216,8 +234,9 @@ function nextHash() {
}

// If possible, use a WeakMap.
// TODO using WeakMap should be true everywhere now that WeakMap is widely supported: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap
const usingWeakMap = typeof WeakMap === 'function';
let weakMap;
let weakMap: WeakMap<object, number> | undefined;
if (usingWeakMap) {
weakMap = new WeakMap();
}
Expand All @@ -226,12 +245,13 @@ const symbolMap = Object.create(null);

let _objHashUID = 0;

let UID_HASH_KEY = '__immutablehash__';
// TODO remove string as Symbol is now widely supported: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol
let UID_HASH_KEY: string | symbol = '__immutablehash__' as const;
if (typeof Symbol === 'function') {
UID_HASH_KEY = Symbol(UID_HASH_KEY);
}

const STRING_HASH_CACHE_MIN_STRLEN = 16;
const STRING_HASH_CACHE_MAX_SIZE = 255;
let STRING_HASH_CACHE_SIZE = 0;
let stringHashCache = {};
let stringHashCache: { [key: string]: number } = {};
84 changes: 0 additions & 84 deletions src/Iterator.js

This file was deleted.

Loading
Loading