1
- // @ts -ignore: decorator
2
- @inline
3
1
export function HASH < T > ( key : T ) : u32 {
4
2
if ( isString < T > ( ) ) {
5
3
return hashStr ( changetype < string > ( key ) ) ;
@@ -10,63 +8,110 @@ export function HASH<T>(key: T): u32 {
10
8
if ( sizeof < T > ( ) == 4 ) return hash32 ( reinterpret < u32 > ( f32 ( key ) ) ) ;
11
9
if ( sizeof < T > ( ) == 8 ) return hash64 ( reinterpret < u64 > ( f64 ( key ) ) ) ;
12
10
} else {
13
- if ( sizeof < T > ( ) == 1 ) return hash8 ( u32 ( key ) ) ;
14
- if ( sizeof < T > ( ) == 2 ) return hash16 ( u32 ( key ) ) ;
15
- if ( sizeof < T > ( ) == 4 ) return hash32 ( u32 ( key ) ) ;
11
+ if ( sizeof < T > ( ) <= 4 ) return hash32 ( u32 ( key ) , sizeof < T > ( ) ) ;
16
12
if ( sizeof < T > ( ) == 8 ) return hash64 ( u64 ( key ) ) ;
17
13
}
18
14
return unreachable ( ) ;
19
15
}
20
16
21
- // FNV-1a 32-bit as a starting point, see: http ://isthe.com/chongo/tech/comp/fnv/
17
+ // XXHash 32-bit as a starting point, see: https ://cyan4973.github.io/xxHash
22
18
19
+ // primes
23
20
// @ts -ignore: decorator
24
- @inline const FNV_OFFSET : u32 = 2166136261 ;
25
-
21
+ @inline const XXH32_P1 : u32 = 2654435761 ;
26
22
// @ts -ignore: decorator
27
- @inline const FNV_PRIME : u32 = 16777619 ;
28
-
29
- function hash8 ( key : u32 ) : u32 {
30
- return ( FNV_OFFSET ^ key ) * FNV_PRIME ;
31
- }
23
+ @inline const XXH32_P2 : u32 = 2246822519 ;
24
+ // @ts -ignore: decorator
25
+ @inline const XXH32_P3 : u32 = 3266489917 ;
26
+ // @ts -ignore: decorator
27
+ @inline const XXH32_P4 : u32 = 668265263 ;
28
+ // @ts -ignore: decorator
29
+ @inline const XXH32_P5 : u32 = 374761393 ;
30
+ // @ts -ignore: decorator
31
+ @inline const XXH32_SEED : u32 = 0 ;
32
32
33
- function hash16 ( key : u32 ) : u32 {
34
- var v = FNV_OFFSET ;
35
- v = ( v ^ ( key & 0xff ) ) * FNV_PRIME ;
36
- v = ( v ^ ( key >> 8 ) ) * FNV_PRIME ;
37
- return v ;
33
+ // @ts -ignore: decorator
34
+ @inline
35
+ function hash32 ( key : u32 , len : u32 = 4 ) : u32 {
36
+ var h : u32 = XXH32_SEED + XXH32_P5 + len ;
37
+ h += key * XXH32_P3 ;
38
+ h = rotl ( h , 17 ) * XXH32_P4 ;
39
+ h ^= h >> 15 ;
40
+ h *= XXH32_P2 ;
41
+ h ^= h >> 13 ;
42
+ h *= XXH32_P3 ;
43
+ h ^= h >> 16 ;
44
+ return h ;
38
45
}
39
46
40
- function hash32 ( key : u32 ) : u32 {
41
- var v = FNV_OFFSET ;
42
- v = ( v ^ ( key & 0xff ) ) * FNV_PRIME ;
43
- v = ( v ^ ( ( key >> 8 ) & 0xff ) ) * FNV_PRIME ;
44
- v = ( v ^ ( ( key >> 16 ) & 0xff ) ) * FNV_PRIME ;
45
- v = ( v ^ ( key >> 24 ) ) * FNV_PRIME ;
46
- return v ;
47
+ // @ts -ignore: decorator
48
+ @inline
49
+ function hash64 ( key : u64 ) : u32 {
50
+ var h : u32 = XXH32_SEED + XXH32_P5 + 8 ;
51
+ h += < u32 > key * XXH32_P3 ;
52
+ h = rotl ( h , 17 ) * XXH32_P4 ;
53
+ h += < u32 > ( key >> 32 ) * XXH32_P3 ;
54
+ h = rotl ( h , 17 ) * XXH32_P4 ;
55
+ h ^= h >> 15 ;
56
+ h *= XXH32_P2 ;
57
+ h ^= h >> 13 ;
58
+ h *= XXH32_P3 ;
59
+ h ^= h >> 16 ;
60
+ return h ;
47
61
}
48
62
49
- function hash64 ( key : u64 ) : u32 {
50
- var l = < u32 > key ;
51
- var h = < u32 > ( key >>> 32 ) ;
52
- var v = FNV_OFFSET ;
53
- v = ( v ^ ( l & 0xff ) ) * FNV_PRIME ;
54
- v = ( v ^ ( ( l >> 8 ) & 0xff ) ) * FNV_PRIME ;
55
- v = ( v ^ ( ( l >> 16 ) & 0xff ) ) * FNV_PRIME ;
56
- v = ( v ^ ( l >> 24 ) ) * FNV_PRIME ;
57
- v = ( v ^ ( h & 0xff ) ) * FNV_PRIME ;
58
- v = ( v ^ ( ( h >> 8 ) & 0xff ) ) * FNV_PRIME ;
59
- v = ( v ^ ( ( h >> 16 ) & 0xff ) ) * FNV_PRIME ;
60
- v = ( v ^ ( h >> 24 ) ) * FNV_PRIME ;
61
- return v ;
63
+ // @ts -ignore: decorator
64
+ @inline
65
+ function mix ( h : u32 , key : u32 ) : u32 {
66
+ return rotl ( h + key * XXH32_P2 , 13 ) * XXH32_P1 ;
62
67
}
63
68
69
+ // @ts -ignore: decorator
70
+ @inline
64
71
function hashStr ( key : string ) : u32 {
65
- var v = FNV_OFFSET ;
66
- if ( key !== null ) {
67
- for ( let i : usize = 0 , k : usize = key . length << 1 ; i < k ; ++ i ) {
68
- v = ( v ^ < u32 > load < u8 > ( changetype < usize > ( key ) + i ) ) * FNV_PRIME ;
72
+ if ( key === null ) return XXH32_SEED ;
73
+
74
+ var h : u32 = key . length << 1 ;
75
+ var len : usize = h ;
76
+ var pos = changetype < usize > ( key ) ;
77
+
78
+ if ( len >= 16 ) {
79
+ let s1 = XXH32_SEED + XXH32_P1 + XXH32_P2 ;
80
+ let s2 = XXH32_SEED + XXH32_P2 ;
81
+ let s3 = XXH32_SEED ;
82
+ let s4 = XXH32_SEED - XXH32_P1 ;
83
+
84
+ let end = len + pos - 16 ;
85
+ while ( pos <= end ) {
86
+ s1 = mix ( s1 , load < u32 > ( pos ) ) ;
87
+ s2 = mix ( s2 , load < u32 > ( pos , 4 ) ) ;
88
+ s3 = mix ( s3 , load < u32 > ( pos , 8 ) ) ;
89
+ s4 = mix ( s4 , load < u32 > ( pos , 12 ) ) ;
90
+ pos += 16 ;
69
91
}
92
+ h += rotl ( s1 , 1 ) + rotl ( s2 , 7 ) + rotl ( s3 , 12 ) + rotl ( s4 , 18 ) ;
93
+ } else {
94
+ h += XXH32_SEED + XXH32_P5 ;
95
+ }
96
+
97
+ var end = changetype < usize > ( key ) + len - 4 ;
98
+ while ( pos <= end ) {
99
+ h += load < u32 > ( pos ) * XXH32_P3 ;
100
+ h = rotl ( h , 17 ) * XXH32_P4 ;
101
+ pos += 4 ;
70
102
}
71
- return v ;
103
+
104
+ end = changetype < usize > ( key ) + len ;
105
+ while ( pos < end ) {
106
+ h += < u32 > load < u8 > ( pos ) * XXH32_P5 ;
107
+ h = rotl ( h , 11 ) * XXH32_P1 ;
108
+ pos ++ ;
109
+ }
110
+
111
+ h ^= h >> 15 ;
112
+ h *= XXH32_P2 ;
113
+ h ^= h >> 13 ;
114
+ h *= XXH32_P3 ;
115
+ h ^= h >> 16 ;
116
+ return h ;
72
117
}
0 commit comments