minhash_rs/
atomic.rs

1use core::hash::{Hash, Hasher};
2use core::{
3    mem::transmute,
4    sync::atomic::{AtomicU16, AtomicU32, AtomicU64, AtomicU8, AtomicUsize},
5};
6
7use fnv::FnvHasher;
8use siphasher::sip128::SipHasher13;
9
10use crate::prelude::*;
11
12pub trait AtomicFetchMin {
13    type Word;
14
15    /// Set the minimum value atomically
16    ///
17    /// # Arguments
18    /// * `value` - The value to set.
19    /// * `ordering` - The ordering to use.
20    ///
21    fn set_min(&self, value: Self::Word, ordering: core::sync::atomic::Ordering);
22}
23
24impl AtomicFetchMin for AtomicU8 {
25    type Word = u8;
26
27    fn set_min(&self, value: Self::Word, ordering: core::sync::atomic::Ordering) {
28        self.fetch_min(value, ordering);
29    }
30}
31
32impl AtomicFetchMin for AtomicU16 {
33    type Word = u16;
34
35    fn set_min(&self, value: Self::Word, ordering: core::sync::atomic::Ordering) {
36        self.fetch_min(value, ordering);
37    }
38}
39
40impl AtomicFetchMin for AtomicU32 {
41    type Word = u32;
42
43    fn set_min(&self, value: Self::Word, ordering: core::sync::atomic::Ordering) {
44        self.fetch_min(value, ordering);
45    }
46}
47
48impl AtomicFetchMin for AtomicU64 {
49    type Word = u64;
50
51    fn set_min(&self, value: Self::Word, ordering: core::sync::atomic::Ordering) {
52        self.fetch_min(value, ordering);
53    }
54}
55
56impl AtomicFetchMin for AtomicUsize {
57    type Word = usize;
58
59    fn set_min(&self, value: Self::Word, ordering: core::sync::atomic::Ordering) {
60        self.fetch_min(value, ordering);
61    }
62}
63
64pub trait IterHashes<Word, const PERMUTATIONS: usize>
65where
66    Word: Min + XorShift + Copy + Eq,
67    u64: Primitive<Word>,
68{
69    /// Iterate on the hashes from the provided value and hasher.
70    ///
71    /// # Arguments
72    /// * `value` - The value to hash.
73    fn iter_hashes_from_value<H: Hash, HS: Hasher>(
74        value: H,
75        mut hasher: HS,
76    ) -> impl Iterator<Item = Word> {
77        // Calculate the hash.
78        value.hash(&mut hasher);
79        let mut hash: Word = hasher.finish().splitmix().splitmix().convert();
80
81        // Iterate over the words.
82        (0..PERMUTATIONS).map(move |_| {
83            hash = hash.xorshift();
84            hash
85        })
86    }
87
88    /// Iterate on the SipHasher13 hashes from the provided value.
89    ///
90    /// # Arguments
91    /// * `value` - The value to hash.
92    ///
93    /// # Examples
94    ///
95    /// ```rust
96    /// use minhash_rs::prelude::*;
97    ///
98    /// let mut minhash = MinHash::<u64, 128>::new();
99    ///
100    /// assert!(!minhash.may_contain_value_with_siphashes13(42));
101    /// minhash.insert_with_siphashes13(42);
102    /// assert!(minhash.may_contain_value_with_siphashes13(42));
103    /// minhash.insert_with_siphashes13(47);
104    /// assert!(minhash.may_contain_value_with_siphashes13(47));
105    /// ```
106    ///  
107    fn iter_siphashes13_from_value<H: Hash>(value: H) -> impl Iterator<Item = Word> {
108        Self::iter_hashes_from_value(value, SipHasher13::new())
109    }
110
111    /// Iterate on the keyed SipHasher13 hashes from the provided value.
112    ///
113    /// # Arguments
114    /// * `value` - The value to hash.
115    /// * `key0` - The first key.
116    /// * `key1` - The second key.
117    ///
118    /// # Examples
119    ///
120    /// ```rust
121    /// use minhash_rs::prelude::*;
122    ///
123    /// let mut minhash = MinHash::<u64, 128>::new();
124    /// let key0 = 0x0123456789ABCDEF;
125    /// let key1 = 0xFEDCBA9876543210;
126    ///
127    /// assert!(!minhash.may_contain_value_with_keyed_siphashes13(42, key0, key1));
128    /// minhash.insert_with_keyed_siphashes13(42, key0, key1);
129    /// assert!(minhash.may_contain_value_with_keyed_siphashes13(42, key0, key1));
130    /// minhash.insert_with_keyed_siphashes13(47, key0, key1);
131    /// assert!(minhash.may_contain_value_with_keyed_siphashes13(47, key0, key1));
132    /// ```
133    ///
134    fn iter_keyed_siphashes13_from_value<H: Hash>(
135        value: H,
136        key0: u64,
137        key1: u64,
138    ) -> impl Iterator<Item = Word> {
139        Self::iter_hashes_from_value(value, SipHasher13::new_with_keys(key0, key1))
140    }
141
142    /// Iterate on the FVN hashes from the provided value.
143    ///
144    /// # Arguments
145    /// * `value` - The value to hash.
146    ///
147    /// # Examples
148    ///
149    /// ```rust
150    /// use minhash_rs::prelude::*;
151    ///
152    /// let mut minhash = MinHash::<u64, 128>::new();
153    ///
154    /// assert!(!minhash.may_contain_value_with_fvn(42));
155    /// minhash.insert_with_fvn(42);
156    /// assert!(minhash.may_contain_value_with_fvn(42));
157    /// minhash.insert_with_fvn(47);
158    /// assert!(minhash.may_contain_value_with_fvn(47));
159    /// ```
160    ///  
161    fn iter_fvn_from_value<H: Hash>(value: H) -> impl Iterator<Item = Word> {
162        Self::iter_hashes_from_value(value, FnvHasher::default())
163    }
164
165    /// Iterate on the keyed SipHasher13 hashes from the provided value.
166    ///
167    /// # Arguments
168    /// * `value` - The value to hash.
169    /// * `key` - The first key.
170    ///
171    /// # Examples
172    ///
173    /// ```rust
174    /// use minhash_rs::prelude::*;
175    ///
176    /// let mut minhash = MinHash::<u64, 128>::new();
177    /// let key = 0x0123456789ABCDEF;
178    ///
179    /// assert!(!minhash.may_contain_value_with_keyed_fvn(42, key));
180    ///
181    fn iter_keyed_fvn_from_value<H: Hash>(value: H, key: u64) -> impl Iterator<Item = Word> {
182        Self::iter_hashes_from_value(value, FnvHasher::with_key(key))
183    }
184}
185
186impl<Word: Min + XorShift + Copy + Eq, const PERMUTATIONS: usize> IterHashes<Word, PERMUTATIONS>
187    for MinHash<Word, PERMUTATIONS>
188where
189    u64: Primitive<Word>,
190{
191}
192
193pub trait AtomicMinHash<AtomicWord: AtomicFetchMin, const PERMUTATIONS: usize>
194where
195    Self: IterHashes<AtomicWord::Word, PERMUTATIONS>,
196    AtomicWord::Word: Min + XorShift + Copy + Eq,
197    u64: Primitive<<AtomicWord as AtomicFetchMin>::Word>,
198    AtomicWord::Word: XorShift + Copy,
199{
200    /// Iterate over the words.
201    fn iter_atomic<'a>(&'a self) -> impl Iterator<Item = &'a AtomicWord>
202    where
203        AtomicWord: 'a,
204        Self: 'a;
205
206    /// Insert a value into the MinHash atomically, with SipHasher13.
207    ///
208    /// # Arguments
209    /// * `value` - The value to insert.
210    ///
211    /// # Examples
212    ///
213    /// ```
214    /// use minhash_rs::prelude::*;
215    ///
216    /// let mut minhash = MinHash::<u64, 4>::new();
217    ///
218    /// assert!(!minhash.may_contain_value_with_siphashes13(42));
219    /// minhash.fetch_insert_with_siphashes13(42, core::sync::atomic::Ordering::Relaxed);
220    /// assert!(!minhash.is_empty());
221    /// assert!(
222    ///     minhash.may_contain_value_with_siphashes13(42),
223    ///     concat!(
224    ///         "The MinHash should contain the value 42, ",
225    ///         "but it does not. The MinHash is: {:?}. ",
226    ///         "The hashes associated to the value 42 are: {:?}."
227    ///     ),
228    ///     minhash,
229    ///     MinHash::<u64, 4>::iter_siphashes13_from_value(42).collect::<Vec<_>>()
230    /// );
231    /// minhash.fetch_insert_with_siphashes13(47, core::sync::atomic::Ordering::Relaxed);
232    /// assert!(minhash.may_contain_value_with_siphashes13(47));
233    ///
234    /// ```
235    ///
236    fn fetch_insert_with_siphashes13<H: Hash>(
237        &self,
238        value: H,
239        ordering: core::sync::atomic::Ordering,
240    ) {
241        // Iterate over the words.
242        for (word, hash) in self
243            .iter_atomic()
244            .zip(Self::iter_siphashes13_from_value(value))
245        {
246            word.set_min(hash, ordering);
247        }
248    }
249
250    /// Insert a value into the MinHash atomically, with keyed SipHasher13.
251    ///
252    /// # Arguments
253    /// * `value` - The value to insert.
254    /// * `key0` - The first key.
255    /// * `key1` - The second key.
256    ///
257    /// # Examples
258    ///
259    /// ```
260    /// use minhash_rs::prelude::*;
261    ///
262    /// let mut minhash = MinHash::<u64, 4>::new();
263    /// let key0 = 0x0123456789ABCDEF;
264    /// let key1 = 0xFEDCBA9876543210;
265    ///
266    /// assert!(!minhash.may_contain_value_with_keyed_siphashes13(42, key0, key1));
267    /// minhash.fetch_insert_with_keyed_siphashes13(42, key0, key1, core::sync::atomic::Ordering::Relaxed);
268    /// assert!(!minhash.is_empty());
269    /// assert!(
270    ///     minhash.may_contain_value_with_keyed_siphashes13(42, key0, key1),
271    ///     concat!(
272    ///         "The MinHash should contain the value 42, ",
273    ///         "but it does not. The MinHash is: {:?}. ",
274    ///         "The hashes associated to the value 42 are: {:?}."
275    ///     ),
276    ///     minhash,
277    ///     MinHash::<u64, 4>::iter_keyed_siphashes13_from_value(42, key0, key1).collect::<Vec<_>>()
278    /// );
279    /// minhash.fetch_insert_with_keyed_siphashes13(47, key0, key1, core::sync::atomic::Ordering::Relaxed);
280    /// assert!(minhash.may_contain_value_with_keyed_siphashes13(47, key0, key1));
281    ///
282    /// ```
283    ///
284    fn fetch_insert_with_keyed_siphashes13<H: Hash>(
285        &self,
286        value: H,
287        key0: u64,
288        key1: u64,
289        ordering: core::sync::atomic::Ordering,
290    ) {
291        // Iterate over the words.
292        for (word, hash) in self
293            .iter_atomic()
294            .zip(Self::iter_keyed_siphashes13_from_value(value, key0, key1))
295        {
296            word.set_min(hash, ordering);
297        }
298    }
299}
300
301impl<const PERMUTATIONS: usize> AtomicMinHash<AtomicU8, PERMUTATIONS>
302    for MinHash<u8, PERMUTATIONS>
303{
304    /// Iterate over the words.
305    fn iter_atomic<'a>(&'a self) -> impl Iterator<Item = &'a AtomicU8>
306    where
307        Self: 'a,
308    {
309        let words: &[AtomicU8] = unsafe { transmute(self.as_ref()) };
310        words.iter()
311    }
312}
313
314impl<const PERMUTATIONS: usize> AtomicMinHash<AtomicU16, PERMUTATIONS>
315    for MinHash<u16, PERMUTATIONS>
316{
317    /// Iterate over the words.
318    fn iter_atomic<'a>(&'a self) -> impl Iterator<Item = &'a AtomicU16>
319    where
320        Self: 'a,
321    {
322        let words: &[AtomicU16] = unsafe { transmute(self.as_ref()) };
323        words.iter()
324    }
325}
326
327impl<const PERMUTATIONS: usize> AtomicMinHash<AtomicU32, PERMUTATIONS>
328    for MinHash<u32, PERMUTATIONS>
329{
330    /// Iterate over the words.
331    fn iter_atomic<'a>(&'a self) -> impl Iterator<Item = &'a AtomicU32>
332    where
333        Self: 'a,
334    {
335        let words: &[AtomicU32] = unsafe { transmute(self.as_ref()) };
336        words.iter()
337    }
338}
339
340impl<const PERMUTATIONS: usize> AtomicMinHash<AtomicU64, PERMUTATIONS>
341    for MinHash<u64, PERMUTATIONS>
342{
343    /// Iterate over the words.
344    fn iter_atomic<'a>(&'a self) -> impl Iterator<Item = &'a AtomicU64>
345    where
346        Self: 'a,
347    {
348        let words: &[AtomicU64] = unsafe { transmute(self.as_ref()) };
349        words.iter()
350    }
351}
352
353impl<const PERMUTATIONS: usize> AtomicMinHash<AtomicUsize, PERMUTATIONS>
354    for MinHash<usize, PERMUTATIONS>
355{
356    /// Iterate over the words.
357    fn iter_atomic<'a>(&'a self) -> impl Iterator<Item = &'a AtomicUsize>
358    where
359        Self: 'a,
360    {
361        let words: &[AtomicUsize] = unsafe { transmute(self.as_ref()) };
362        words.iter()
363    }
364}