use core::hash::{BuildHasher, Hasher};
const K: u64 = 0x9E37_79B9_7F4A_7C15;
#[derive(Default, Clone, Copy, Debug)]
pub struct CoordBuildHasher;
impl BuildHasher for CoordBuildHasher {
type Hasher = CoordHasher;
#[inline]
fn build_hasher(&self) -> CoordHasher {
CoordHasher(0)
}
}
#[derive(Clone, Copy, Debug)]
pub struct CoordHasher(u64);
impl Hasher for CoordHasher {
#[inline]
fn finish(&self) -> u64 {
self.0
}
#[inline]
fn write(&mut self, bytes: &[u8]) {
let mut state = self.0;
for &b in bytes {
state = (state ^ b as u64).wrapping_mul(K);
}
self.0 = state;
}
#[inline]
fn write_u64(&mut self, n: u64) {
let x = (self.0 ^ n).rotate_left(27).wrapping_mul(K);
self.0 = x ^ (x >> 32);
}
#[inline]
fn write_u32(&mut self, n: u32) {
self.write_u64(n as u64);
}
#[inline]
fn write_u16(&mut self, n: u16) {
self.write_u64(n as u64);
}
#[inline]
fn write_u8(&mut self, n: u8) {
self.write_u64(n as u64);
}
#[inline]
fn write_usize(&mut self, n: usize) {
self.write_u64(n as u64);
}
#[inline]
fn write_i64(&mut self, n: i64) {
self.write_u64(n as u64);
}
#[inline]
fn write_i32(&mut self, n: i32) {
self.write_u64(n as u64);
}
}
pub type CoordHashMap<K, V> = std::collections::HashMap<K, V, CoordBuildHasher>;
pub type CoordHashSet<K> = std::collections::HashSet<K, CoordBuildHasher>;
#[cfg(test)]
mod tests {
use super::*;
use crate::Coord;
use std::collections::HashMap;
#[test]
fn basic_insert_lookup() {
let mut m: CoordHashMap<Coord, u32> = HashMap::default();
for r in 0..1000u32 {
m.insert(Coord::new(r, r % 64), r);
}
for r in 0..1000u32 {
assert_eq!(m.get(&Coord::new(r, r % 64)), Some(&r));
}
assert_eq!(m.len(), 1000);
}
#[test]
fn distinct_coords_produce_distinct_hashes() {
fn h(c: Coord) -> u64 {
CoordBuildHasher.hash_one(c)
}
let a = h(Coord::new(0, 0));
let b = h(Coord::new(0, 1));
let c = h(Coord::new(1, 0));
assert_ne!(a, b);
assert_ne!(a, c);
assert_ne!(b, c);
}
}