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, ARBITRARY4};
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<'a> {
16 pub(crate) inner: fast::FoldHasher<'a>,
17}
18
19impl<'a> FoldHasher<'a> {
20 /// Initializes this [`FoldHasher`] with the given per-hasher seed and
21 /// [`SharedSeed`].
22 #[inline(always)]
23 pub const fn with_seed(per_hasher_seed: u64, shared_seed: &'a SharedSeed) -> FoldHasher<'a> {
24 FoldHasher {
25 inner: fast::FoldHasher::with_seed(per_hasher_seed, shared_seed),
26 }
27 }
28}
29
30impl<'a> Hasher for FoldHasher<'a> {
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 #[cfg(feature = "nightly")]
67 #[inline(always)]
68 fn write_str(&mut self, s: &str) {
69 self.inner.write_str(s);
70 }
71
72 #[inline(always)]
73 fn finish(&self) -> u64 {
74 folded_multiply(self.inner.finish(), ARBITRARY0)
75 }
76}
77
78/// A [`BuildHasher`] for [`quality::FoldHasher`](FoldHasher) that is randomly initialized.
79#[derive(Clone, Default, Debug)]
80pub struct RandomState {
81 inner: fast::RandomState,
82}
83
84impl BuildHasher for RandomState {
85 type Hasher = FoldHasher<'static>;
86
87 #[inline(always)]
88 fn build_hasher(&self) -> FoldHasher<'static> {
89 FoldHasher {
90 inner: self.inner.build_hasher(),
91 }
92 }
93}
94
95/// A [`BuildHasher`] for [`quality::FoldHasher`](FoldHasher) that is randomly
96/// initialized by default, but can also be initialized with a specific seed.
97///
98/// This can be useful for e.g. testing, but the downside is that this type
99/// has a size of 16 bytes rather than the 8 bytes [`RandomState`] is.
100#[derive(Clone, Default, Debug)]
101pub struct SeedableRandomState {
102 inner: fast::SeedableRandomState,
103}
104
105impl SeedableRandomState {
106 /// Generates a random [`SeedableRandomState`], similar to [`RandomState`].
107 #[inline(always)]
108 pub fn random() -> Self {
109 Self {
110 inner: fast::SeedableRandomState::random(),
111 }
112 }
113
114 /// Generates a fixed [`SeedableRandomState`], similar to [`FixedState`].
115 #[inline(always)]
116 pub fn fixed() -> Self {
117 Self {
118 inner: fast::SeedableRandomState::fixed(),
119 }
120 }
121
122 /// Generates a [`SeedableRandomState`] with the given per-hasher seed
123 /// and [`SharedSeed`].
124 #[inline(always)]
125 pub fn with_seed(per_hasher_seed: u64, shared_seed: &'static SharedSeed) -> Self {
126 Self {
127 // We do an additional folded multiply with the seed here for
128 // the quality hash to ensure better independence between seed
129 // and hash.
130 inner: fast::SeedableRandomState::with_seed(
131 folded_multiply(per_hasher_seed, ARBITRARY4),
132 shared_seed,
133 ),
134 }
135 }
136}
137
138impl BuildHasher for SeedableRandomState {
139 type Hasher = FoldHasher<'static>;
140
141 #[inline(always)]
142 fn build_hasher(&self) -> FoldHasher<'static> {
143 FoldHasher {
144 inner: self.inner.build_hasher(),
145 }
146 }
147}
148
149/// A [`BuildHasher`] for [`quality::FoldHasher`](FoldHasher) that always has the same fixed seed.
150///
151/// Not recommended unless you absolutely need determinism.
152#[derive(Clone, Default, Debug)]
153pub struct FixedState {
154 inner: fast::FixedState,
155}
156
157impl FixedState {
158 /// Creates a [`FixedState`] with the given per-hasher seed.
159 #[inline(always)]
160 pub const fn with_seed(per_hasher_seed: u64) -> Self {
161 Self {
162 // We do an additional folded multiply with the seed here for
163 // the quality hash to ensure better independence between seed
164 // and hash. If the seed is zero the folded multiply is zero,
165 // preserving with_seed(0) == default().
166 inner: fast::FixedState::with_seed(per_hasher_seed:folded_multiply(x:per_hasher_seed, ARBITRARY4)),
167 }
168 }
169}
170
171impl BuildHasher for FixedState {
172 type Hasher = FoldHasher<'static>;
173
174 #[inline(always)]
175 fn build_hasher(&self) -> FoldHasher<'static> {
176 FoldHasher {
177 inner: self.inner.build_hasher(),
178 }
179 }
180}
181