1- use crate :: utils:: hasher:: rapidhash:: { rapidhash_known , rapidhash_nano} ;
1+ use crate :: utils:: hasher:: rapidhash:: rapidhash_nano;
22use std:: collections:: HashMap ;
33use std:: hash:: { BuildHasher , Hasher } ;
4+ use std:: u64;
5+
6+ use super :: rapidhash:: finish;
7+
8+ const DEFAULT_SEED : u64 = 0 ;
49
510/// reimplementation of rapidhash nano from [GitHub](https://github.com/Nicoshev/rapidhash/blob/master/rapidhash.h#L432)
611/// (nano because were basically never gonna be hashing more than 48 bytes)
712/// probably overkill but its really fast and i was bored.
8- # [ derive ( Default ) ]
13+ /// these hashes are NOT portable for primitive ints.
914pub struct RapidHasher {
1015 state : u64 ,
1116}
@@ -17,15 +22,6 @@ pub struct RapidHasher {
1722/// This should also be faster than the default so maybe it could be used in place of the default for anythign that doesnt need the added security of the default hashing.
1823pub type DeterministicHashMap < K , V > = HashMap < K , V , RapidHasher > ;
1924
20- macro_rules! write_num {
21- ( $name: ident, $ty: ty) => {
22- #[ inline( always) ]
23- fn $name( & mut self , i: $ty) {
24- self . state = rapidhash_known( & i. to_le_bytes( ) )
25- }
26- } ;
27- }
28-
2925impl Hasher for RapidHasher {
3026 #[ inline( always) ]
3127 fn finish ( & self ) -> u64 {
@@ -34,28 +30,70 @@ impl Hasher for RapidHasher {
3430
3531 #[ inline( always) ]
3632 fn write ( & mut self , bytes : & [ u8 ] ) {
37- self . state = rapidhash_nano ( bytes)
38- }
39-
40- // these can be optimized down to not convert to and from their bytes...
41- write_num ! ( write_u8, u8 ) ;
42- write_num ! ( write_u16, u16 ) ;
43- write_num ! ( write_u32, u32 ) ;
44- write_num ! ( write_u64, u64 ) ;
45- write_num ! ( write_u128, u128 ) ;
46- write_num ! ( write_usize, usize ) ;
47- write_num ! ( write_i8, i8 ) ;
48- write_num ! ( write_i16, i16 ) ;
49- write_num ! ( write_i32, i32 ) ;
50- write_num ! ( write_i64, i64 ) ;
51- write_num ! ( write_i128, i128 ) ;
52- write_num ! ( write_isize, isize ) ;
33+ self . state = rapidhash_nano ( self . state , bytes)
34+ }
35+
36+ #[ inline( always) ]
37+ fn write_u8 ( & mut self , i : u8 ) {
38+ let ( a, b) = ( ( ( i as u64 ) << 45 ) | i as u64 , i as u64 ) ;
39+ self . state = finish ( a, b, self . state , 1 ) ;
40+ }
41+
42+ #[ inline( always) ]
43+ fn write_u16 ( & mut self , i : u16 ) {
44+ let ( hi, lo) = ( ( i >> 8 ) as u64 , ( i & 0xFF ) as u64 ) ;
45+ self . state = finish ( ( hi << 45 ) | lo, lo, self . state , 2 ) ;
46+ }
47+
48+ #[ inline( always) ]
49+ fn write_u32 ( & mut self , i : u32 ) {
50+ self . state = write_32 ( self . state ^ 4 , i) ;
51+ }
52+
53+ #[ inline( always) ]
54+ fn write_u64 ( & mut self , i : u64 ) {
55+ self . state = write_64 ( self . state ^ 8 , i) ;
56+ }
57+
58+ #[ inline( always) ]
59+ fn write_u128 ( & mut self , i : u128 ) {
60+ let ( a, b) = ( ( i >> 64 ) as u64 , i as u64 ) ; // mask is done automatically by casting down
61+ self . state = finish ( a, b, self . state ^ 16 , 16 ) ;
62+ }
63+
64+ #[ inline( always) ]
65+ fn write_usize ( & mut self , i : usize ) {
66+ self . state = if size_of :: < usize > ( ) == 4 {
67+ write_32 ( self . state ^ 4 , i as u32 )
68+ } else {
69+ write_64 ( self . state ^ 8 , i as u64 )
70+ } ;
71+ }
72+ }
73+
74+ impl Default for RapidHasher {
75+ fn default ( ) -> Self {
76+ Self {
77+ state : DEFAULT_SEED
78+ }
79+ }
5380}
5481
82+
5583impl BuildHasher for RapidHasher {
5684 type Hasher = Self ;
5785
5886 fn build_hasher ( & self ) -> Self :: Hasher {
5987 Self :: default ( )
6088 }
89+ }
90+
91+ #[ inline( always) ]
92+ const fn write_64 ( seed : u64 , i : u64 ) -> u64 {
93+ finish ( i >> 32 , i & 0xFFFF_FFFF , seed, 8 )
94+ }
95+
96+ #[ inline( always) ]
97+ const fn write_32 ( seed : u64 , i : u32 ) -> u64 { // no mask stuff is needed since for 4 bits it just reads both as the same...
98+ finish ( i as u64 , i as u64 , seed, 4 )
6199}
0 commit comments