Skip to main content

zrip_core/
hash.rs

1#![forbid(unsafe_code)]
2
3pub const PRIME32_1: u32 = 0x9E37_79B1;
4pub const PRIME32_2: u32 = 0x85EB_CA77;
5pub const PRIME64_1: u64 = 0x9E37_79B1_85EB_CA87;
6
7#[inline]
8pub fn hash4(value: u32, hash_log: u32) -> u32 {
9    (value.wrapping_mul(PRIME32_1)) >> (32 - hash_log)
10}
11
12#[inline]
13pub fn hash5(value: u64, hash_log: u32) -> u32 {
14    ((value << 24).wrapping_mul(PRIME64_1) >> (64 - hash_log)) as u32
15}
16
17#[inline]
18pub fn hash6(value: u64, hash_log: u32) -> u32 {
19    ((value << 16).wrapping_mul(PRIME64_1) >> (64 - hash_log)) as u32
20}
21
22#[inline]
23pub fn hash7(value: u64, hash_log: u32) -> u32 {
24    ((value << 8).wrapping_mul(PRIME64_1) >> (64 - hash_log)) as u32
25}
26
27#[inline]
28pub fn hash8(value: u64, hash_log: u32) -> u32 {
29    (value.wrapping_mul(PRIME64_1) >> (64 - hash_log)) as u32
30}
31
32#[cfg(test)]
33mod tests {
34    use super::*;
35
36    #[test]
37    fn hash4_distributes() {
38        let mut buckets = [0u32; 256];
39        for i in 0..4096u32 {
40            let h = hash4(i, 8) as usize;
41            buckets[h] += 1;
42        }
43        let used = buckets.iter().filter(|&&c| c > 0).count();
44        assert!(used > 200, "hash4 only hit {used}/256 buckets");
45    }
46
47    #[test]
48    fn hash8_distributes() {
49        let mut buckets = [0u32; 256];
50        for i in 0..4096u64 {
51            let h = hash8(i, 8) as usize;
52            buckets[h] += 1;
53        }
54        let used = buckets.iter().filter(|&&c| c > 0).count();
55        assert!(used > 200, "hash8 only hit {used}/256 buckets");
56    }
57}