@@ -123,6 +123,32 @@ proc hiXorLo(a, b: uint64): uint64 {.inline.} =
123123 else :
124124 result = hiXorLoFallback64 (a, b)
125125
126+ when defined (js):
127+ import std/ jsbigints
128+ import std/ private/ jsutils
129+
130+ proc hiXorLoJs (a, b: JsBigInt ): JsBigInt =
131+ let
132+ prod = a * b
133+ mask = big " 0xffffffffffffffff" # (big"1" shl big"64") - big"1"
134+ result = (prod shr big " 64" ) xor (prod and mask)
135+
136+ template hashWangYiJS (x: JsBigInt ): Hash =
137+ let
138+ P0 = big " 0xa0761d6478bd642f"
139+ P1 = big " 0xe7037ed1a0b428db"
140+ P58 = big " 0xeb44accab455d16d" # big"0xeb44accab455d165" xor big"8"
141+ res = hiXorLoJs (hiXorLoJs (P0 , x xor P1 ), P58 )
142+ cast [Hash ](toNumber (wrapToInt (res, 32 )))
143+
144+ template asBigInt (num: float ): JsBigInt =
145+ let
146+ x = newArrayBuffer (8 )
147+ y = newFloat64Array (x)
148+ z = newBigUint64Array (x)
149+ y[0 ] = num
150+ z[0 ]
151+
126152proc hashWangYi1 * (x: int64 | uint64 | Hash ): Hash {.inline .} =
127153 # # Wang Yi's hash_v1 for 64-bit ints (see https://github.com/rurban/smhasher for
128154 # # more details). This passed all scrambling tests in Spring 2019 and is simple.
@@ -139,22 +165,10 @@ proc hashWangYi1*(x: int64|uint64|Hash): Hash {.inline.} =
139165 result = cast [Hash ](h (x))
140166 else :
141167 when defined (js):
142- asm """
143- if (typeof BigInt == 'undefined') {
144- ` result` = ` x` ; // For Node < 10.4, etc. we do the old identity hash
145- } else { // Otherwise we match the low 32-bits of C/C++ hash
146- function hi_xor_lo_js(a, b) {
147- const prod = BigInt(a) * BigInt(b);
148- const mask = (BigInt(1) << BigInt(64)) - BigInt(1);
149- return (prod >> BigInt(64)) ^ (prod & mask);
150- }
151- const P0 = BigInt(0xa0761d64)<<BigInt(32)|BigInt(0x78bd642f);
152- const P1 = BigInt(0xe7037ed1)<<BigInt(32)|BigInt(0xa0b428db);
153- const P58 = BigInt(0xeb44acca)<<BigInt(32)|BigInt(0xb455d165)^BigInt(8);
154- var res = hi_xor_lo_js(hi_xor_lo_js(P0, BigInt(` x` ) ^ P1), P58);
155- ` result` = Number(res & ((BigInt(1) << BigInt(53)) - BigInt(1)));
156- } """
157- result = result and cast [Hash ](0x FFFFFFFF )
168+ if hasJsBigInt ():
169+ result = hashWangYiJS (big (x))
170+ else :
171+ result = cast [Hash ](x) and cast [Hash ](0x FFFFFFFF )
158172 else :
159173 result = cast [Hash ](h (x))
160174
@@ -213,18 +227,6 @@ else:
213227 # # Efficient hashing of integers.
214228 hashWangYi1 (uint64 (ord (x)))
215229
216- when defined (js):
217- proc asBigInt (x: float ): int64 =
218- # result is a `BigInt` type in js, but we cheat the type system
219- # and say it is a `int64` type.
220- # TODO : refactor it using bigInt once jsBigInt is ready, pending pr #1640
221- asm """
222- const buffer = new ArrayBuffer(8);
223- const floatBuffer = new Float64Array(buffer);
224- const uintBuffer = new BigUint64Array(buffer);
225- floatBuffer[0] = ` x` ;
226- ` result` = uintBuffer[0]; """
227-
228230proc hash * (x: float ): Hash {.inline .} =
229231 # # Efficient hashing of floats.
230232 let y = x + 0.0 # for denormalization
@@ -235,7 +237,7 @@ proc hash*(x: float): Hash {.inline.} =
235237 when not defined (js):
236238 result = hashWangYi1 (cast [Hash ](y))
237239 else :
238- result = hashWangYi1 (asBigInt (y))
240+ result = hashWangYiJS (asBigInt (y))
239241
240242# Forward declarations before methods that hash containers. This allows
241243# containers to contain other containers
0 commit comments