1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
use std::hash::{BuildHasher, Hasher};
/// A hasher implementation specialized for thread IDs.
pub(crate) struct ThreadIdHasher {
state: u64,
}
impl ThreadIdHasher {
pub(crate) fn new() -> Self {
Self { state: 0 }
}
}
impl Hasher for ThreadIdHasher {
fn finish(&self) -> u64 {
self.state
}
// No mutation - we avoid hardcoding hash logic into tests, so expectations are minimal.
#[cfg_attr(test, mutants::skip)]
fn write(&mut self, bytes: &[u8]) {
assert_eq!(
bytes.len(),
8,
"ThreadIdHasher expects exactly 8 bytes (u64) as input"
);
// We expect this to only be called once per hash operation.
// We expect the contents to be a u64 that typically has only
// the low bits set (rare to see more than 16 bits of data, often even 8 bits).
self.state = u64::from_le_bytes(bytes.try_into().expect("expecting ThreadId to be u64"));
// We copy the low byte into the high byte because HashMap seems to care a lot about
// the high bits (this is used as the control byte for fast comparisons).
self.state ^= u64::from(
*bytes
.first()
.expect("already asserted that we have enough bytes"),
) << 56;
}
}
/// A `BuildHasher` that creates `ThreadIdHasher` instances.
pub(crate) struct BuildThreadIdHasher;
impl BuildHasher for BuildThreadIdHasher {
type Hasher = ThreadIdHasher;
fn build_hasher(&self) -> Self::Hasher {
ThreadIdHasher::new()
}
}
#[cfg(test)]
#[cfg_attr(coverage_nightly, coverage(off))]
mod tests {
use super::*;
#[test]
fn control_byte_is_different() {
// Even for tiny changes in the ID value, we expect the control byte (high byte) to be
// different because the control byte comparison is performance-critical.
let mut hasher = ThreadIdHasher::new();
hasher.write(&0_u64.to_le_bytes());
let hash1 = hasher.finish();
let mut hasher = ThreadIdHasher::new();
hasher.write(&1_u64.to_le_bytes());
let hash2 = hasher.finish();
// There has to be at least some difference.
assert_ne!(hash1, hash2);
// This is the control byte (high byte).
assert_ne!(hash1 & 0xFF00_0000_0000_0000, hash2 & 0xFF00_0000_0000_0000);
}
}