1//! The foldhash implementation optimized for quality.
2
3use core::hash::{BuildHasher, Hasher};
4
5use crate::seed::SharedSeed;
6
7use 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)]
15pub struct FoldHasher {
16 pub(crate) inner: fast::FoldHasher,
17}
18
19impl FoldHasher {
20 /// Initializes this [`FoldHasher`] with the given per-hasher seed and
21 /// [`SharedSeed`].
22 #[inline(always)]
23 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
30impl Hasher for FoldHasher {
31 #[inline(always)]
32 fn write(&mut self, bytes: &[u8]) {
33 self.inner.write(bytes);
34 }
35
36 #[inline(always)]
37 fn write_u8(&mut self, i: u8) {
38 self.inner.write_u8(i);
39 }
40
41 #[inline(always)]
42 fn write_u16(&mut self, i: u16) {
43 self.inner.write_u16(i);
44 }
45
46 #[inline(always)]
47 fn write_u32(&mut self, i: u32) {
48 self.inner.write_u32(i);
49 }
50
51 #[inline(always)]
52 fn write_u64(&mut self, i: u64) {
53 self.inner.write_u64(i);
54 }
55
56 #[inline(always)]
57 fn write_u128(&mut self, i: u128) {
58 self.inner.write_u128(i);
59 }
60
61 #[inline(always)]
62 fn write_usize(&mut self, i: usize) {
63 self.inner.write_usize(i);
64 }
65
66 #[inline(always)]
67 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)]
74pub struct RandomState {
75 inner: fast::RandomState,
76}
77
78impl BuildHasher for RandomState {
79 type Hasher = FoldHasher;
80
81 #[inline(always)]
82 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)]
95pub struct SeedableRandomState {
96 inner: fast::SeedableRandomState,
97}
98
99impl SeedableRandomState {
100 /// Generates a random [`SeedableRandomState`], similar to [`RandomState`].
101 #[inline(always)]
102 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)]
110 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)]
119 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
132impl BuildHasher for SeedableRandomState {
133 type Hasher = FoldHasher;
134
135 #[inline(always)]
136 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)]
147pub struct FixedState {
148 inner: fast::FixedState,
149}
150
151impl FixedState {
152 /// Creates a [`FixedState`] with the given per-hasher seed.
153 #[inline(always)]
154 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(per_hasher_seed:folded_multiply(x:per_hasher_seed, ARBITRARY8)),
161 }
162 }
163}
164
165impl BuildHasher for FixedState {
166 type Hasher = FoldHasher;
167
168 #[inline(always)]
169 fn build_hasher(&self) -> FoldHasher {
170 FoldHasher {
171 inner: self.inner.build_hasher(),
172 }
173 }
174}
175