use std::hash::Hash; use boxcar; use dashmap::DashMap; pub struct Interner where V: Copy + Eq + Hash, I: Copy + Into, { map: DashMap, store: boxcar::Vec, } impl Interner where V: Copy + Eq + Hash, I: Copy + From + Into, { pub fn new() -> Self { return Interner { map: DashMap::new(), store: boxcar::Vec::with_capacity(1024), }; } pub fn get(&self, key: I) -> V { return self.store[key.into()]; } pub fn intern(&self, value: V) -> I { if let Some(key) = self.map.get(&value) { return *key; } let key = self.store.push(value).into(); self.map.insert(value, key); return key; } } #[cfg(test)] mod tests { use super::Interner; use crate::unistr::UniStr; #[test] fn test_interner_intern() { let xs = [UniStr("fishi"), UniStr("fishi"), UniStr("fishᵢ")]; let y = UniStr("andy"); let mut interner = Interner::<_, usize>::new(); for i in 0..xs.len() { for j in i..xs.len() { assert_eq!(interner.intern(xs[i]), interner.intern(xs[j])); } } for i in 0..xs.len() { assert_ne!(interner.intern(y), interner.intern(xs[i])); } } #[test] fn test_interner_gets_first_inserted() { let mut interner = Interner::<_, usize>::new(); let xs = [UniStr("fishi"), UniStr("fishi"), UniStr("fishᵢ")]; let ys = xs.iter().map(|&x| interner.intern(x)).collect::>(); for i in 0..ys.len() { assert_eq!(interner.get(ys[i]), xs[0]); } } }