1- // @ts -ignore: decorator
2- @inline
31export function HASH < T > ( key : T ) : u32 {
42 if ( isString < T > ( ) ) {
53 return hashStr ( changetype < string > ( key ) ) ;
@@ -10,63 +8,110 @@ export function HASH<T>(key: T): u32 {
108 if ( sizeof < T > ( ) == 4 ) return hash32 ( reinterpret < u32 > ( f32 ( key ) ) ) ;
119 if ( sizeof < T > ( ) == 8 ) return hash64 ( reinterpret < u64 > ( f64 ( key ) ) ) ;
1210 } 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 > ( ) ) ;
1612 if ( sizeof < T > ( ) == 8 ) return hash64 ( u64 ( key ) ) ;
1713 }
1814 return unreachable ( ) ;
1915}
2016
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
2218
19+ // primes
2320// @ts -ignore: decorator
24- @inline const FNV_OFFSET : u32 = 2166136261 ;
25-
21+ @inline const XXH32_P1 : u32 = 2654435761 ;
2622// @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 ;
3232
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 ;
3845}
3946
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 ;
4761}
4862
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 ;
6267}
6368
69+ // @ts -ignore: decorator
70+ @inline
6471function 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 ;
6991 }
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 ;
70102 }
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 ;
72117}
0 commit comments