• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! The foldhash implementation optimized for quality.
2 
3 use core::hash::{BuildHasher, Hasher};
4 
5 use crate::seed::SharedSeed;
6 
7 use crate::{fast, folded_multiply, ARBITRARY0, ARBITRARY8};
8 
9 /// A [`Hasher`] instance implementing foldhash, optimized for quality.
10 ///
11 /// While you can create one directly with [`FoldHasher::with_seed`], you
12 /// most likely want to use [`RandomState`], [`SeedableRandomState`] or
13 /// [`FixedState`] to create [`FoldHasher`]s.
14 #[derive(Clone)]
15 pub struct FoldHasher {
16     pub(crate) inner: fast::FoldHasher,
17 }
18 
19 impl FoldHasher {
20     /// Initializes this [`FoldHasher`] with the given per-hasher seed and
21     /// [`SharedSeed`].
22     #[inline(always)]
with_seed(per_hasher_seed: u64, shared_seed: &SharedSeed) -> FoldHasher23     pub fn with_seed(per_hasher_seed: u64, shared_seed: &SharedSeed) -> FoldHasher {
24         FoldHasher {
25             inner: fast::FoldHasher::with_seed(per_hasher_seed, shared_seed),
26         }
27     }
28 }
29 
30 impl Hasher for FoldHasher {
31     #[inline(always)]
write(&mut self, bytes: &[u8])32     fn write(&mut self, bytes: &[u8]) {
33         self.inner.write(bytes);
34     }
35 
36     #[inline(always)]
write_u8(&mut self, i: u8)37     fn write_u8(&mut self, i: u8) {
38         self.inner.write_u8(i);
39     }
40 
41     #[inline(always)]
write_u16(&mut self, i: u16)42     fn write_u16(&mut self, i: u16) {
43         self.inner.write_u16(i);
44     }
45 
46     #[inline(always)]
write_u32(&mut self, i: u32)47     fn write_u32(&mut self, i: u32) {
48         self.inner.write_u32(i);
49     }
50 
51     #[inline(always)]
write_u64(&mut self, i: u64)52     fn write_u64(&mut self, i: u64) {
53         self.inner.write_u64(i);
54     }
55 
56     #[inline(always)]
write_u128(&mut self, i: u128)57     fn write_u128(&mut self, i: u128) {
58         self.inner.write_u128(i);
59     }
60 
61     #[inline(always)]
write_usize(&mut self, i: usize)62     fn write_usize(&mut self, i: usize) {
63         self.inner.write_usize(i);
64     }
65 
66     #[inline(always)]
finish(&self) -> u6467     fn finish(&self) -> u64 {
68         folded_multiply(self.inner.finish(), ARBITRARY0)
69     }
70 }
71 
72 /// A [`BuildHasher`] for [`quality::FoldHasher`](FoldHasher) that is randomly initialized.
73 #[derive(Copy, Clone, Default, Debug)]
74 pub struct RandomState {
75     inner: fast::RandomState,
76 }
77 
78 impl BuildHasher for RandomState {
79     type Hasher = FoldHasher;
80 
81     #[inline(always)]
build_hasher(&self) -> FoldHasher82     fn build_hasher(&self) -> FoldHasher {
83         FoldHasher {
84             inner: self.inner.build_hasher(),
85         }
86     }
87 }
88 
89 /// A [`BuildHasher`] for [`quality::FoldHasher`](FoldHasher) that is randomly
90 /// initialized by default, but can also be initialized with a specific seed.
91 ///
92 /// This can be useful for e.g. testing, but the downside is that this type
93 /// has a size of 16 bytes rather than the 8 bytes [`RandomState`] is.
94 #[derive(Copy, Clone, Default, Debug)]
95 pub struct SeedableRandomState {
96     inner: fast::SeedableRandomState,
97 }
98 
99 impl SeedableRandomState {
100     /// Generates a random [`SeedableRandomState`], similar to [`RandomState`].
101     #[inline(always)]
random() -> Self102     pub fn random() -> Self {
103         Self {
104             inner: fast::SeedableRandomState::random(),
105         }
106     }
107 
108     /// Generates a fixed [`SeedableRandomState`], similar to [`FixedState`].
109     #[inline(always)]
fixed() -> Self110     pub fn fixed() -> Self {
111         Self {
112             inner: fast::SeedableRandomState::fixed(),
113         }
114     }
115 
116     /// Generates a [`SeedableRandomState`] with the given per-hasher seed
117     /// and [`SharedSeed`].
118     #[inline(always)]
with_seed(per_hasher_seed: u64, shared_seed: &'static SharedSeed) -> Self119     pub fn with_seed(per_hasher_seed: u64, shared_seed: &'static SharedSeed) -> Self {
120         Self {
121             // We do an additional folded multiply with the seed here for
122             // the quality hash to ensure better independence between seed
123             // and hash.
124             inner: fast::SeedableRandomState::with_seed(
125                 folded_multiply(per_hasher_seed, ARBITRARY8),
126                 shared_seed,
127             ),
128         }
129     }
130 }
131 
132 impl BuildHasher for SeedableRandomState {
133     type Hasher = FoldHasher;
134 
135     #[inline(always)]
build_hasher(&self) -> FoldHasher136     fn build_hasher(&self) -> FoldHasher {
137         FoldHasher {
138             inner: self.inner.build_hasher(),
139         }
140     }
141 }
142 
143 /// A [`BuildHasher`] for [`quality::FoldHasher`](FoldHasher) that always has the same fixed seed.
144 ///
145 /// Not recommended unless you absolutely need determinism.
146 #[derive(Copy, Clone, Default, Debug)]
147 pub struct FixedState {
148     inner: fast::FixedState,
149 }
150 
151 impl FixedState {
152     /// Creates a [`FixedState`] with the given per-hasher seed.
153     #[inline(always)]
with_seed(per_hasher_seed: u64) -> Self154     pub const fn with_seed(per_hasher_seed: u64) -> Self {
155         Self {
156             // We do an additional folded multiply with the seed here for
157             // the quality hash to ensure better independence between seed
158             // and hash. If the seed is zero the folded multiply is zero,
159             // preserving with_seed(0) == default().
160             inner: fast::FixedState::with_seed(folded_multiply(per_hasher_seed, ARBITRARY8)),
161         }
162     }
163 }
164 
165 impl BuildHasher for FixedState {
166     type Hasher = FoldHasher;
167 
168     #[inline(always)]
build_hasher(&self) -> FoldHasher169     fn build_hasher(&self) -> FoldHasher {
170         FoldHasher {
171             inner: self.inner.build_hasher(),
172         }
173     }
174 }
175