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