1
1
// @ts -ignore: decorator
2
2
@inline
3
- export function HASH < T > ( key : T ) : u32 {
3
+ export function HASH < T > ( key : T ) : u64 {
4
4
if ( isString < T > ( ) ) {
5
5
return hashStr ( changetype < string > ( key ) ) ;
6
6
} else if ( isReference < T > ( ) ) {
@@ -10,63 +10,128 @@ export function HASH<T>(key: T): u32 {
10
10
if ( sizeof < T > ( ) == 4 ) return hash32 ( reinterpret < u32 > ( f32 ( key ) ) ) ;
11
11
if ( sizeof < T > ( ) == 8 ) return hash64 ( reinterpret < u64 > ( f64 ( key ) ) ) ;
12
12
} 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 ) ) ;
13
+ if ( sizeof < T > ( ) <= 4 ) return hash32 ( u32 ( key ) ) ;
16
14
if ( sizeof < T > ( ) == 8 ) return hash64 ( u64 ( key ) ) ;
17
15
}
18
16
return unreachable ( ) ;
19
17
}
20
18
21
- // FNV-1a 32-bit as a starting point, see: http ://isthe.com/chongo/tech/comp/fnv/
19
+ // XXHash 32-bit as a starting point, see: https ://cyan4973.github.io/xxHash
22
20
21
+ // primes
23
22
// @ts -ignore: decorator
24
- @inline const FNV_OFFSET : u32 = 2166136261 ;
25
-
23
+ @inline const XXH64_P1 : u64 = 11400714785074694791 ;
24
+ // @ts -ignore: decorator
25
+ @inline const XXH64_P2 : u64 = 14029467366897019727 ;
26
+ // @ts -ignore: decorator
27
+ @inline const XXH64_P3 : u64 = 1609587929392839161 ;
26
28
// @ts -ignore: decorator
27
- @inline const FNV_PRIME : u32 = 16777619 ;
29
+ @inline const XXH64_P4 : u64 = 9650029242287828579 ;
30
+ // @ts -ignore: decorator
31
+ @inline const XXH64_P5 : u64 = 2870177450012600261 ;
32
+ // @ts -ignore: decorator
33
+ @inline const XXH64_SEED : u64 = 0 ;
28
34
29
- function hash8 ( key : u32 ) : u32 {
30
- return ( FNV_OFFSET ^ key ) * FNV_PRIME ;
35
+ function hash32 ( key : u32 ) : u64 {
36
+ var h : u64 = XXH64_SEED + XXH64_P5 + 4 ;
37
+ h ^= u64 ( key ) * XXH64_P1 ;
38
+ h = rotl ( h , 23 ) * XXH64_P2 + XXH64_P3 ;
39
+ h ^= h >> 33 ;
40
+ h *= XXH64_P2 ;
41
+ h ^= h >> 29 ;
42
+ h *= XXH64_P3 ;
43
+ h ^= h >> 32 ;
44
+ return h ;
31
45
}
32
46
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 ;
47
+ function hash64 ( key : u64 ) : u64 {
48
+ var h : u64 = XXH64_SEED + XXH64_P5 + 8 ;
49
+ h ^= rotl ( key * XXH64_P2 , 31 ) * XXH64_P1 ;
50
+ h = rotl ( h , 27 ) * XXH64_P1 + XXH64_P4 ;
51
+ h ^= h >> 33 ;
52
+ h *= XXH64_P2 ;
53
+ h ^= h >> 29 ;
54
+ h *= XXH64_P3 ;
55
+ h ^= h >> 32 ;
56
+ return h ;
38
57
}
39
58
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 ;
59
+ // @ts -ignore: decorator
60
+ @inline
61
+ function mix1 ( h : u64 , key : u64 ) : u64 {
62
+ return rotl ( h + key * XXH64_P2 , 31 ) * XXH64_P1 ;
47
63
}
48
64
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 ;
65
+ // @ts -ignore: decorator
66
+ @inline
67
+ function mix2 ( h : u64 , s : u64 ) : u64 {
68
+ return ( h ^ ( rotl ( s , 31 ) * XXH64_P1 ) ) * XXH64_P1 + XXH64_P4 ;
62
69
}
63
70
64
- 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 ;
71
+ function hashStr ( key : string ) : u64 {
72
+ if ( key === null ) {
73
+ return XXH64_SEED ;
74
+ }
75
+ var len = key . length << 1 ;
76
+ var h : u64 = XXH64_SEED + XXH64_P5 + u64 ( len ) ;
77
+
78
+ if ( len >= 32 ) {
79
+ let s1 = XXH64_SEED + XXH64_P1 + XXH64_P2 ;
80
+ let s2 = XXH64_SEED + XXH64_P2 ;
81
+ let s3 = XXH64_SEED ;
82
+ let s4 = XXH64_SEED - XXH64_P1 ;
83
+
84
+ let i = 0 ;
85
+ len -= 32 ;
86
+
87
+ while ( i <= len ) {
88
+ s1 = mix1 ( s1 , load < u64 > ( changetype < usize > ( key ) + i ) ) ;
89
+ s2 = mix1 ( s2 , load < u64 > ( changetype < usize > ( key ) + i , 8 ) ) ;
90
+ s3 = mix1 ( s3 , load < u64 > ( changetype < usize > ( key ) + i , 16 ) ) ;
91
+ s4 = mix1 ( s4 , load < u64 > ( changetype < usize > ( key ) + i , 24 ) ) ;
92
+ i += 32 ;
69
93
}
94
+ h = rotl ( s1 , 1 ) + rotl ( s2 , 7 ) + rotl ( s3 , 12 ) + rotl ( s4 , 18 ) ;
95
+
96
+ s1 *= XXH64_P2 ;
97
+ s2 *= XXH64_P2 ;
98
+ s3 *= XXH64_P2 ;
99
+ s4 *= XXH64_P2 ;
100
+
101
+ h = mix2 ( h , s1 ) ;
102
+ h = mix2 ( h , s2 ) ;
103
+ h = mix2 ( h , s3 ) ;
104
+ h = mix2 ( h , s4 ) ;
105
+
106
+ h += u64 ( len ) ;
107
+ len -= i ;
108
+ }
109
+
110
+ var i = 0 ;
111
+ len -= 8 ;
112
+
113
+ while ( i <= len ) {
114
+ h ^= rotl ( load < u64 > ( changetype < usize > ( key ) + i ) * XXH64_P2 , 31 ) * XXH64_P1 ;
115
+ h = rotl ( h , 27 ) * XXH64_P1 + XXH64_P4 ;
116
+ i += 8 ;
117
+ }
118
+
119
+ if ( i + 4 <= len ) {
120
+ h ^= < u64 > load < u32 > ( changetype < usize > ( key ) + i ) * XXH64_P1 ;
121
+ h = rotl ( h , 23 ) * XXH64_P2 + XXH64_P3 ;
122
+ i += 4 ;
70
123
}
71
- return v ;
124
+
125
+ while ( i < len ) {
126
+ h += < u64 > load < u8 > ( changetype < usize > ( key ) + i ) * XXH64_P5 ;
127
+ h = rotl ( h , 11 ) * XXH64_P1 ;
128
+ i ++ ;
129
+ }
130
+
131
+ h ^= h >> 33 ;
132
+ h *= XXH64_P2 ;
133
+ h ^= h >> 29 ;
134
+ h *= XXH64_P3 ;
135
+ h ^= h >> 32 ;
136
+ return h ;
72
137
}
0 commit comments