|
| 1 | +const FNV_OFFSET_BASIS: u64 = 0xcbf2_9ce4_8422_2325; |
| 2 | +const FNV_PRIME: u64 = 0x0000_0100_0000_01b3; |
| 3 | + |
| 4 | +#[must_use] |
| 5 | +pub fn fnv1a64(bytes: &[u8]) -> u64 { |
| 6 | + let mut hash = FNV_OFFSET_BASIS; |
| 7 | + for &byte in bytes { |
| 8 | + hash ^= u64::from(byte); |
| 9 | + hash = hash.wrapping_mul(FNV_PRIME); |
| 10 | + } |
| 11 | + hash |
| 12 | +} |
| 13 | + |
| 14 | +#[must_use] |
| 15 | +pub fn fold_f64(acc: u64, value: f64) -> u64 { |
| 16 | + let mut hash = if acc == 0 { FNV_OFFSET_BASIS } else { acc }; |
| 17 | + for &byte in &value.to_bits().to_le_bytes() { |
| 18 | + hash ^= u64::from(byte); |
| 19 | + hash = hash.wrapping_mul(FNV_PRIME); |
| 20 | + } |
| 21 | + hash |
| 22 | +} |
| 23 | + |
| 24 | +#[cfg(test)] |
| 25 | +mod tests { |
| 26 | + use super::*; |
| 27 | + #[test] |
| 28 | + fn matches_the_published_fnv1a64_vectors() { |
| 29 | + assert_eq!(fnv1a64(b""), 0xcbf2_9ce4_8422_2325); |
| 30 | + assert_eq!(fnv1a64(b"a"), 0xaf63_dc4c_8601_ec8c); |
| 31 | + assert_eq!(fnv1a64(b"foobar"), 0x8594_4171_f739_67e8); |
| 32 | + } |
| 33 | + #[test] |
| 34 | + fn the_fold_is_order_sensitive() { |
| 35 | + let a = fold_f64(fold_f64(0, 1.5), 2.5); |
| 36 | + let b = fold_f64(fold_f64(0, 2.5), 1.5); |
| 37 | + assert_ne!(a, b, "fold must depend on order; an XOR fold would not"); |
| 38 | + } |
| 39 | + #[test] |
| 40 | + fn the_fold_depends_on_the_value() { |
| 41 | + assert_ne!(fold_f64(0, 1.5), fold_f64(0, 1.5000000000000002)); |
| 42 | + } |
| 43 | +} |
0 commit comments