3
3
use core:: hash:: { BuildHasher , Hasher } ;
4
4
5
5
use crate :: seed:: { gen_per_hasher_seed, GlobalSeed , SharedSeed } ;
6
- use crate :: { folded_multiply, hash_bytes_long , hash_bytes_medium , rotate_right, ARBITRARY3 } ;
6
+ use crate :: { folded_multiply, hash_bytes_short , hash_bytes_long , rotate_right, ARBITRARY3 } ;
7
7
8
8
/// A [`Hasher`] instance implementing foldhash, optimized for speed.
9
9
///
10
10
/// While you can create one directly with [`FoldHasher::with_seed`], you
11
11
/// most likely want to use [`RandomState`], [`SeedableRandomState`] or
12
12
/// [`FixedState`] to create [`FoldHasher`]s.
13
13
#[ derive( Clone ) ]
14
- pub struct FoldHasher {
14
+ pub struct FoldHasher < ' a > {
15
15
accumulator : u64 ,
16
16
sponge : u128 ,
17
17
sponge_len : u8 ,
18
- fold_seed : u64 ,
19
- expand_seed : u64 ,
20
- expand_seed2 : u64 ,
21
- expand_seed3 : u64 ,
18
+ seeds : & ' a [ u64 ; 4 ] ,
22
19
}
23
20
24
- impl FoldHasher {
21
+ impl < ' a > FoldHasher < ' a > {
25
22
/// Initializes this [`FoldHasher`] with the given per-hasher seed and
26
23
/// [`SharedSeed`].
27
24
#[ inline]
28
- pub fn with_seed ( per_hasher_seed : u64 , shared_seed : & SharedSeed ) -> FoldHasher {
25
+ pub fn with_seed ( per_hasher_seed : u64 , shared_seed : & ' a SharedSeed ) -> FoldHasher < ' a > {
29
26
FoldHasher {
30
27
accumulator : per_hasher_seed,
31
28
sponge : 0 ,
32
29
sponge_len : 0 ,
33
- fold_seed : shared_seed. seeds [ 0 ] ,
34
- expand_seed : shared_seed. seeds [ 1 ] ,
35
- expand_seed2 : shared_seed. seeds [ 2 ] ,
36
- expand_seed3 : shared_seed. seeds [ 3 ] ,
30
+ seeds : & shared_seed. seeds ,
37
31
}
38
32
}
39
33
@@ -43,7 +37,7 @@ impl FoldHasher {
43
37
if self . sponge_len as usize + bits > 128 {
44
38
let lo = self . sponge as u64 ;
45
39
let hi = ( self . sponge >> 64 ) as u64 ;
46
- self . accumulator = folded_multiply ( lo ^ self . accumulator , hi ^ self . fold_seed ) ;
40
+ self . accumulator = folded_multiply ( lo ^ self . accumulator , hi ^ self . seeds [ 0 ] ) ;
47
41
self . sponge = x. into ( ) ;
48
42
self . sponge_len = bits as u8 ;
49
43
} else {
@@ -53,7 +47,7 @@ impl FoldHasher {
53
47
}
54
48
}
55
49
56
- impl Hasher for FoldHasher {
50
+ impl < ' a > Hasher for FoldHasher < ' a > {
57
51
#[ inline( always) ]
58
52
fn write ( & mut self , bytes : & [ u8 ] ) {
59
53
// We perform overlapping reads in the byte hash which could lead to
@@ -62,41 +56,11 @@ impl Hasher for FoldHasher {
62
56
// which costs only a single cycle (or none if executed with
63
57
// instruction-level parallelism).
64
58
let len = bytes. len ( ) ;
65
- let base_seed = rotate_right ( self . accumulator , len as u32 ) ;
59
+ self . accumulator = rotate_right ( self . accumulator , len as u32 ) ;
66
60
if len <= 16 {
67
- let mut s0 = base_seed;
68
- let mut s1 = self . expand_seed ;
69
- // XOR the input into s0, s1, then multiply and fold.
70
- if len >= 8 {
71
- s0 ^= u64:: from_ne_bytes ( bytes[ 0 ..8 ] . try_into ( ) . unwrap ( ) ) ;
72
- s1 ^= u64:: from_ne_bytes ( bytes[ len - 8 ..] . try_into ( ) . unwrap ( ) ) ;
73
- } else if len >= 4 {
74
- s0 ^= u32:: from_ne_bytes ( bytes[ 0 ..4 ] . try_into ( ) . unwrap ( ) ) as u64 ;
75
- s1 ^= u32:: from_ne_bytes ( bytes[ len - 4 ..] . try_into ( ) . unwrap ( ) ) as u64 ;
76
- } else if len > 0 {
77
- let lo = bytes[ 0 ] ;
78
- let mid = bytes[ len / 2 ] ;
79
- let hi = bytes[ len - 1 ] ;
80
- s0 ^= lo as u64 ;
81
- s1 ^= ( ( hi as u64 ) << 8 ) | mid as u64 ;
82
- }
83
- self . accumulator = folded_multiply ( s0, s1) ;
84
- } else if len < 256 {
85
- self . accumulator = hash_bytes_medium (
86
- bytes,
87
- base_seed,
88
- base_seed. wrapping_add ( self . expand_seed ) ,
89
- self . fold_seed ,
90
- ) ;
61
+ self . accumulator = hash_bytes_short ( bytes, self . accumulator , self . seeds ) ;
91
62
} else {
92
- self . accumulator = hash_bytes_long (
93
- bytes,
94
- base_seed,
95
- base_seed. wrapping_add ( self . expand_seed ) ,
96
- base_seed. wrapping_add ( self . expand_seed2 ) ,
97
- base_seed. wrapping_add ( self . expand_seed3 ) ,
98
- self . fold_seed ,
99
- ) ;
63
+ self . accumulator = hash_bytes_long ( bytes, self . accumulator , self . seeds ) ;
100
64
}
101
65
}
102
66
@@ -124,7 +88,7 @@ impl Hasher for FoldHasher {
124
88
fn write_u128 ( & mut self , i : u128 ) {
125
89
let lo = i as u64 ;
126
90
let hi = ( i >> 64 ) as u64 ;
127
- self . accumulator = folded_multiply ( lo ^ self . accumulator , hi ^ self . fold_seed ) ;
91
+ self . accumulator = folded_multiply ( lo ^ self . accumulator , hi ^ self . seeds [ 0 ] ) ;
128
92
}
129
93
130
94
#[ inline( always) ]
@@ -141,7 +105,7 @@ impl Hasher for FoldHasher {
141
105
if self . sponge_len > 0 {
142
106
let lo = self . sponge as u64 ;
143
107
let hi = ( self . sponge >> 64 ) as u64 ;
144
- folded_multiply ( lo ^ self . accumulator , hi ^ self . fold_seed )
108
+ folded_multiply ( lo ^ self . accumulator , hi ^ self . seeds [ 0 ] )
145
109
} else {
146
110
self . accumulator
147
111
}
@@ -166,10 +130,10 @@ impl Default for RandomState {
166
130
}
167
131
168
132
impl BuildHasher for RandomState {
169
- type Hasher = FoldHasher ;
133
+ type Hasher = FoldHasher < ' static > ;
170
134
171
135
#[ inline( always) ]
172
- fn build_hasher ( & self ) -> FoldHasher {
136
+ fn build_hasher ( & self ) -> FoldHasher < ' static > {
173
137
FoldHasher :: with_seed ( self . per_hasher_seed , self . global_seed . get ( ) )
174
138
}
175
139
}
@@ -224,10 +188,10 @@ impl SeedableRandomState {
224
188
}
225
189
226
190
impl BuildHasher for SeedableRandomState {
227
- type Hasher = FoldHasher ;
191
+ type Hasher = FoldHasher < ' static > ;
228
192
229
193
#[ inline( always) ]
230
- fn build_hasher ( & self ) -> FoldHasher {
194
+ fn build_hasher ( & self ) -> FoldHasher < ' static > {
231
195
FoldHasher :: with_seed ( self . per_hasher_seed , self . shared_seed )
232
196
}
233
197
}
@@ -261,10 +225,10 @@ impl Default for FixedState {
261
225
}
262
226
263
227
impl BuildHasher for FixedState {
264
- type Hasher = FoldHasher ;
228
+ type Hasher = FoldHasher < ' static > ;
265
229
266
230
#[ inline( always) ]
267
- fn build_hasher ( & self ) -> FoldHasher {
231
+ fn build_hasher ( & self ) -> FoldHasher < ' static > {
268
232
FoldHasher :: with_seed ( self . per_hasher_seed , SharedSeed :: global_fixed ( ) )
269
233
}
270
234
}
0 commit comments