massa_models/prehash.rs
1// Copyright (c) 2022 MASSA LABS <info@massa.net>
2
3use std::collections::{HashMap, HashSet};
4use std::hash::{BuildHasherDefault, Hasher};
5use std::marker::PhantomData;
6
7impl PreHashed for massa_hash::Hash {}
8
9/// A trait indicating that its carrier is already a hash with at least 64 bits
10/// and doesn't need to be re-hashed for hash-table purposes
11pub trait PreHashed {}
12
13/// A `Hasher` for `PreHashed` keys that is faster because it avoids re-hashing hashes but simply truncates them.
14/// Note: when truncating, it takes the last 8 bytes of the key instead of the first 8 bytes.
15/// This is done to circumvent biases induced by first-byte manipulations in addresses related to the thread assignment process
16pub struct HashMapper<T: PreHashed> {
17 source: PhantomData<T>,
18 hash: u64,
19}
20
21/// Default implementation for `HashMapper` (zero hash)
22impl<T: PreHashed> Default for HashMapper<T> {
23 fn default() -> Self {
24 HashMapper {
25 source: Default::default(),
26 hash: Default::default(),
27 }
28 }
29}
30
31/// `Hasher` implementation for `HashMapper`
32impl<T: PreHashed> Hasher for HashMapper<T> {
33 /// finish the hashing process and return the truncated `u64` hash
34 #[inline]
35 fn finish(&self) -> u64 {
36 self.hash
37 }
38
39 /// write the bytes of a `PreHashed` key into the `HashMapper`
40 /// Panics if `bytes.len()` is strictly lower than 8
41 /// Note: the truncated `u64` is completely overwritten by the last 8 items of "bytes" at every call
42 #[inline]
43 fn write(&mut self, bytes: &[u8]) {
44 // assumes bytes.len() is at least 8, otherwise panics
45 self.hash = u64::from_ne_bytes(
46 bytes[bytes.len().checked_sub(8).unwrap()..]
47 .try_into()
48 .unwrap(),
49 );
50 }
51}
52
53/// `BuildHasherDefault` specialization for `HashMapper`
54pub type BuildHashMapper<T> = BuildHasherDefault<HashMapper<T>>;
55
56/// `HashMap` specialization for `PreHashed` keys
57/// This hashmap is about 2x faster than the default `HashMap`
58pub type PreHashMap<K, V> = HashMap<K, V, BuildHashMapper<K>>;
59
60/// `HashSet` specialization for `PreHashed` keys
61/// This hashset is about 2x faster than the default `HashSet`
62pub type PreHashSet<T> = HashSet<T, BuildHashMapper<T>>;
63
64/// Trait allowing pre-allocations
65pub trait CapacityAllocator {
66 /// pre-allocate with a given capacity
67 fn with_capacity(capacity: usize) -> Self;
68}
69
70impl<K: PreHashed, V> CapacityAllocator for PreHashMap<K, V> {
71 /// pre-allocate with a given capacity
72 fn with_capacity(capacity: usize) -> Self {
73 PreHashMap::with_capacity_and_hasher(capacity, BuildHashMapper::default())
74 }
75}
76
77impl<K: PreHashed> CapacityAllocator for PreHashSet<K> {
78 /// pre-allocate with a given capacity
79 fn with_capacity(capacity: usize) -> Self {
80 PreHashSet::with_capacity_and_hasher(capacity, BuildHashMapper::default())
81 }
82}