use std::collections::HashMap;
use std::hash::{BuildHasherDefault, Hasher};
pub(crate) type Names<T> = HashMap<&'static str, T, BuildHasherDefault<Words>>;
#[derive(Debug, Default)]
pub(crate) struct Words(u64);
impl Words {
fn mix(&mut self, word: u64) {
self.0 = (self.0.rotate_left(5) ^ word).wrapping_mul(0x9e37_79b9_7f4a_7c15);
}
}
impl Hasher for Words {
fn finish(&self) -> u64 {
self.0
}
fn write(&mut self, bytes: &[u8]) {
for chunk in bytes.chunks(8) {
let mut word = [0; 8];
word[..chunk.len()].copy_from_slice(chunk);
self.mix(u64::from_le_bytes(word));
}
}
fn write_u8(&mut self, byte: u8) {
self.mix(u64::from(byte));
}
}
pub(crate) fn index<T>(table: &[(&'static str, T)]) -> Names<usize> {
let mut at = Names::with_capacity_and_hasher(table.len(), BuildHasherDefault::default());
for (number, &(name, _)) in table.iter().enumerate() {
at.entry(name).or_insert(number);
}
at
}
pub(crate) fn every<T>(table: &[T], name: impl Fn(&T) -> &'static str) -> Names<Vec<usize>> {
let mut at: Names<Vec<usize>> = Names::default();
for (number, entry) in table.iter().enumerate() {
at.entry(name(entry)).or_default().push(number);
}
at
}