use std::collections::HashMap;
use std::hash::Hash;
pub(crate) struct CornerWeld<K> {
seen: HashMap<K, u32, foldhash::fast::RandomState>,
}
impl<K: Eq + Hash> CornerWeld<K> {
pub(crate) fn with_capacity(corners: usize) -> Self {
Self {
seen: HashMap::with_capacity_and_hasher(corners, Default::default()),
}
}
pub(crate) fn intern(&mut self, key: K) -> (u32, bool) {
let next = self.seen.len() as u32;
match self.seen.entry(key) {
std::collections::hash_map::Entry::Occupied(entry) => (*entry.get(), false),
std::collections::hash_map::Entry::Vacant(entry) => {
entry.insert(next);
(next, true)
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ids_are_dense_and_follow_first_appearance() {
let mut weld: CornerWeld<u32> = CornerWeld::with_capacity(4);
assert_eq!(weld.intern(7), (0, true));
assert_eq!(weld.intern(3), (1, true));
assert_eq!(weld.intern(7), (0, false));
assert_eq!(weld.intern(9), (2, true));
}
#[test]
fn two_welds_of_the_same_keys_agree() {
let keys = [5u32, 1, 5, 2, 1, 9];
let ids = |()| {
let mut weld: CornerWeld<u32> = CornerWeld::with_capacity(keys.len());
keys.iter().map(|k| weld.intern(*k).0).collect::<Vec<_>>()
};
assert_eq!(ids(()), ids(()));
assert_eq!(ids(()), vec![0, 1, 0, 2, 1, 3]);
}
}