UNPKG

6.55 kBJavaScriptView Raw
1/**
2 * @license
3 * Copyright 2021 Google LLC. All Rights Reserved.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 * =============================================================================
16 */
17// Workaround for allowing cjs module to be included in bundle created by
18// rollup.
19import * as LongExports from 'long';
20// tslint:disable-next-line
21const Long =
22// tslint:disable-next-line
23LongExports.default || LongExports;
24export function hexToLong(hex) {
25 return Long.fromString(hex, true, 16);
26}
27// Some primes between 2^63 and 2^64 for various uses.
28// Hex 0xc3a5c85c97cb3127
29const k0 = hexToLong('c3a5c85c97cb3127');
30// Hex 0xb492b66fbe98f273
31const k1 = hexToLong('b492b66fbe98f273');
32// Hex 0x9ae16a3b2f90404f
33const k2 = hexToLong('9ae16a3b2f90404f');
34function shiftMix(val) {
35 return val.xor(val.shru(47));
36}
37function fetch(s, offset, numBytes) {
38 const bytes = s.slice(offset, offset + numBytes);
39 return Long.fromBytes(Array.from(bytes), true, true);
40}
41function fetch64(s, offset) {
42 return fetch(s, offset, 8);
43}
44function fetch32(s, offset) {
45 return fetch(s, offset, 4);
46}
47function rotate64(val, shift) {
48 // Avoid shifting by 64: doing so yields an undefined result.
49 return shift === 0 ? val : val.shru(shift).or(val.shl(64 - shift));
50}
51function hashLen16(u, v, mul = hexToLong('9ddfea08eb382d69')) {
52 // Murmur-inspired hashing.
53 let a = u.xor(v).mul(mul);
54 a = a.xor(a.shru(47));
55 let b = v.xor(a).mul(mul);
56 b = b.xor(b.shru(47));
57 b = b.mul(mul);
58 return b;
59}
60// Return a 16-byte hash for 48 bytes. Quick and dirty.
61// Callers do best to use "random-looking" values for a and b.
62function weakHashLen32WithSeeds(w, x, y, z, a, b) {
63 a = a.add(w);
64 b = rotate64(b.add(a).add(z), 21);
65 const c = a;
66 a = a.add(x);
67 a = a.add(y);
68 b = b.add(rotate64(a, 44));
69 return [a.add(z), b.add(c)];
70}
71function weakHashLen32WithSeedsStr(s, offset, a, b) {
72 return weakHashLen32WithSeeds(fetch64(s, offset), fetch64(s, offset + 8), fetch64(s, offset + 16), fetch64(s, offset + 24), a, b);
73}
74function hashLen0to16(s, len = s.length) {
75 if (len >= 8) {
76 const mul = k2.add(len * 2);
77 const a = fetch64(s, 0).add(k2);
78 const b = fetch64(s, len - 8);
79 const c = rotate64(b, 37).mul(mul).add(a);
80 const d = rotate64(a, 25).add(b).mul(mul);
81 return hashLen16(c, d, mul);
82 }
83 if (len >= 4) {
84 const mul = k2.add(len * 2);
85 const a = fetch32(s, 0);
86 return hashLen16(a.shl(3).add(len), fetch32(s, len - 4), mul);
87 }
88 if (len > 0) {
89 const a = s[0];
90 const b = s[len >> 1];
91 const c = s[len - 1];
92 const y = a + (b << 8);
93 const z = len + (c << 2);
94 return shiftMix(k2.mul(y).xor(k0.mul(z))).mul(k2);
95 }
96 return k2;
97}
98function hashLen17to32(s, len = s.length) {
99 const mul = k2.add(len * 2);
100 const a = fetch64(s, 0).mul(k1);
101 const b = fetch64(s, 8);
102 const c = fetch64(s, len - 8).mul(mul);
103 const d = fetch64(s, len - 16).mul(k2);
104 return hashLen16(rotate64(a.add(b), 43).add(rotate64(c, 30)).add(d), a.add(rotate64(b.add(k2), 18)).add(c), mul);
105}
106function hashLen33to64(s, len = s.length) {
107 const mul = k2.add(len * 2);
108 const a = fetch64(s, 0).mul(k2);
109 const b = fetch64(s, 8);
110 const c = fetch64(s, len - 8).mul(mul);
111 const d = fetch64(s, len - 16).mul(k2);
112 const y = rotate64(a.add(b), 43).add(rotate64(c, 30)).add(d);
113 const z = hashLen16(y, a.add(rotate64(b.add(k2), 18)).add(c), mul);
114 const e = fetch64(s, 16).mul(mul);
115 const f = fetch64(s, 24);
116 const g = y.add(fetch64(s, len - 32)).mul(mul);
117 const h = z.add(fetch64(s, len - 24)).mul(mul);
118 return hashLen16(rotate64(e.add(f), 43).add(rotate64(g, 30)).add(h), e.add(rotate64(f.add(a), 18)).add(g), mul);
119}
120export function fingerPrint64(s, len = s.length) {
121 const seed = Long.fromNumber(81, true);
122 if (len <= 32) {
123 if (len <= 16) {
124 return hashLen0to16(s, len);
125 }
126 else {
127 return hashLen17to32(s, len);
128 }
129 }
130 else if (len <= 64) {
131 return hashLen33to64(s, len);
132 }
133 // For strings over 64 bytes we loop. Internal state consists of
134 // 56 bytes: v, w, x, y, and z.
135 let x = seed;
136 let y = seed.mul(k1).add(113);
137 let z = shiftMix(y.mul(k2).add(113)).mul(k2);
138 let v = [Long.UZERO, Long.UZERO];
139 let w = [Long.UZERO, Long.UZERO];
140 x = x.mul(k2).add(fetch64(s, 0));
141 let offset = 0;
142 // Set end so that after the loop we have 1 to 64 bytes left to process.
143 const end = ((len - 1) >> 6) * 64;
144 const last64 = end + ((len - 1) & 63) - 63;
145 do {
146 x = rotate64(x.add(y).add(v[0]).add(fetch64(s, offset + 8)), 37).mul(k1);
147 y = rotate64(y.add(v[1]).add(fetch64(s, offset + 48)), 42).mul(k1);
148 x = x.xor(w[1]);
149 y = y.add(v[0]).add(fetch64(s, offset + 40));
150 z = rotate64(z.add(w[0]), 33).mul(k1);
151 v = weakHashLen32WithSeedsStr(s, offset, v[1].mul(k1), x.add(w[0]));
152 w = weakHashLen32WithSeedsStr(s, offset + 32, z.add(w[1]), y.add(fetch64(s, offset + 16)));
153 [z, x] = [x, z];
154 offset += 64;
155 } while (offset !== end);
156 const mul = k1.add(z.and(0xff).shl(1));
157 // Point to the last 64 bytes of input.
158 offset = last64;
159 w[0] = w[0].add((len - 1) & 63);
160 v[0] = v[0].add(w[0]);
161 w[0] = w[0].add(v[0]);
162 x = rotate64(x.add(y).add(v[0]).add(fetch64(s, offset + 8)), 37).mul(mul);
163 y = rotate64(y.add(v[1]).add(fetch64(s, offset + 48)), 42).mul(mul);
164 x = x.xor(w[1].mul(9));
165 y = y.add(v[0].mul(9).add(fetch64(s, offset + 40)));
166 z = rotate64(z.add(w[0]), 33).mul(mul);
167 v = weakHashLen32WithSeedsStr(s, offset, v[1].mul(mul), x.add(w[0]));
168 w = weakHashLen32WithSeedsStr(s, offset + 32, z.add(w[1]), y.add(fetch64(s, offset + 16)));
169 [z, x] = [x, z];
170 return hashLen16(hashLen16(v[0], w[0], mul).add(shiftMix(y).mul(k0)).add(z), hashLen16(v[1], w[1], mul).add(x), mul);
171}
172//# sourceMappingURL=hash_util.js.map
\No newline at end of file