1use std::hash::{Hash, Hasher};
2
3use crate::nulls::IsNull;
4
5#[inline(always)]
7pub fn _boost_hash_combine(l: u64, r: u64) -> u64 {
8 l ^ r.wrapping_add(0x9e3779b9u64.wrapping_add(l << 6).wrapping_add(r >> 2))
9}
10
11#[inline(always)]
12pub const fn folded_multiply(a: u64, b: u64) -> u64 {
13 let full = (a as u128).wrapping_mul(b as u128);
14 (full as u64) ^ ((full >> 64) as u64)
15}
16
17#[derive(Eq, Copy, Clone, Debug)]
21pub struct BytesHash<'a> {
22 payload: Option<&'a [u8]>,
23 pub(super) hash: u64,
24}
25
26impl<'a> BytesHash<'a> {
27 #[inline]
28 pub fn new(s: Option<&'a [u8]>, hash: u64) -> Self {
29 Self { payload: s, hash }
30 }
31}
32
33impl<'a> IsNull for BytesHash<'a> {
34 const HAS_NULLS: bool = true;
35 type Inner = BytesHash<'a>;
36
37 #[inline(always)]
38 fn is_null(&self) -> bool {
39 self.payload.is_none()
40 }
41
42 fn unwrap_inner(self) -> Self::Inner {
43 assert!(self.payload.is_some());
44 self
45 }
46}
47
48impl Hash for BytesHash<'_> {
49 #[inline]
50 fn hash<H: Hasher>(&self, state: &mut H) {
51 state.write_u64(self.hash)
52 }
53}
54
55impl PartialEq for BytesHash<'_> {
56 #[inline]
57 fn eq(&self, other: &Self) -> bool {
58 (self.hash == other.hash) && (self.payload == other.payload)
59 }
60}
61
62#[inline(always)]
63pub fn hash_to_partition(h: u64, n_partitions: usize) -> usize {
64 ((h as u128 * n_partitions as u128) >> 64) as usize
70}
71
72#[derive(Clone)]
73pub struct HashPartitioner {
74 num_partitions: usize,
75 seed: u64,
76}
77
78impl HashPartitioner {
79 #[inline]
82 pub fn new(num_partitions: usize, mut seed: u64) -> Self {
83 assert!(num_partitions > 0);
84 const ARBITRARY1: u64 = 0x85921e81c41226a0;
86 const ARBITRARY2: u64 = 0x3bc1d0faba166294;
87 const ARBITRARY3: u64 = 0xfbde893e21a73756;
88 seed = folded_multiply(seed ^ ARBITRARY1, ARBITRARY2);
89 seed = folded_multiply(seed, ARBITRARY3);
90 seed |= 1;
91 Self {
92 seed,
93 num_partitions,
94 }
95 }
96
97 #[inline(always)]
102 pub fn hash_to_partition(&self, hash: u64) -> usize {
103 let shuffled = hash.wrapping_mul(self.seed);
109 ((shuffled as u128 * self.num_partitions as u128) >> 64) as usize
110 }
111
112 #[inline(always)]
114 pub fn null_partition(&self) -> usize {
115 0
116 }
117
118 #[inline(always)]
119 pub fn num_partitions(&self) -> usize {
120 self.num_partitions
121 }
122}
123
124pub trait DirtyHash {
126 fn dirty_hash(&self) -> u64;
129}
130
131const RANDOM_ODD: u64 = 0x55fbfd6bfc5458e9;
134const RANDOM_ODD2: u64 = 0x495705b285852baf;
135
136macro_rules! impl_hash_partition_as_u64 {
137 ($T: ty) => {
138 impl DirtyHash for $T {
139 #[inline(always)]
140 fn dirty_hash(&self) -> u64 {
141 (*self as u64).wrapping_mul(RANDOM_ODD)
142 }
143 }
144 };
145}
146
147impl_hash_partition_as_u64!(u8);
148impl_hash_partition_as_u64!(u16);
149impl_hash_partition_as_u64!(u32);
150impl_hash_partition_as_u64!(u64);
151impl_hash_partition_as_u64!(i8);
152impl_hash_partition_as_u64!(i16);
153impl_hash_partition_as_u64!(i32);
154impl_hash_partition_as_u64!(i64);
155
156impl DirtyHash for u128 {
157 #[inline(always)]
158 fn dirty_hash(&self) -> u64 {
159 let lo = *self as u64;
160 let hi = (*self >> 64) as u64;
161 let hlo = lo.wrapping_mul(RANDOM_ODD);
162 let hhi = hi.wrapping_mul(RANDOM_ODD2);
163 hlo.wrapping_add(hhi)
164 }
165}
166
167impl DirtyHash for i128 {
168 #[inline(always)]
169 fn dirty_hash(&self) -> u64 {
170 let lo = *self as u64;
171 let hi = (*self as u128 >> 64) as u64;
172 let hlo = lo.wrapping_mul(RANDOM_ODD);
173 let hhi = hi.wrapping_mul(RANDOM_ODD2);
174 hlo.wrapping_add(hhi)
175 }
176}
177
178impl DirtyHash for BytesHash<'_> {
179 #[inline(always)]
180 fn dirty_hash(&self) -> u64 {
181 self.hash
182 }
183}
184
185impl<T: DirtyHash + ?Sized> DirtyHash for &T {
186 #[inline(always)]
187 fn dirty_hash(&self) -> u64 {
188 (*self).dirty_hash()
189 }
190}
191
192impl<T: DirtyHash> DirtyHash for Option<T> {
195 #[inline(always)]
196 fn dirty_hash(&self) -> u64 {
197 self.as_ref().map(|s| s.dirty_hash()).unwrap_or(0)
198 }
199}