use rustc_hash::FxHashMap as HashMap;
use crate::object::NameId;
pub struct NameTable {
names: Vec<Vec<u8>>,
lookup: HashMap<Vec<u8>, NameId>,
}
impl NameTable {
pub fn new() -> Self {
Self {
names: Vec::new(),
lookup: HashMap::default(),
}
}
pub fn intern(&mut self, name: &[u8]) -> NameId {
if let Some(&id) = self.lookup.get(name) {
return id;
}
let id = NameId(self.names.len() as u32);
self.names.push(name.to_vec());
self.lookup.insert(name.to_vec(), id);
id
}
pub fn get_bytes(&self, id: NameId) -> &[u8] {
&self.names[id.0 as usize]
}
pub fn find(&self, name: &[u8]) -> Option<NameId> {
self.lookup.get(name).copied()
}
}
impl Default for NameTable {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_intern_and_lookup() {
let mut table = NameTable::new();
let id1 = table.intern(b"add");
let id2 = table.intern(b"sub");
let id3 = table.intern(b"add");
assert_eq!(id1, id3);
assert_ne!(id1, id2);
assert_eq!(table.get_bytes(id1), b"add");
assert_eq!(table.get_bytes(id2), b"sub");
}
#[test]
fn test_find() {
let mut table = NameTable::new();
assert_eq!(table.find(b"foo"), None);
let id = table.intern(b"foo");
assert_eq!(table.find(b"foo"), Some(id));
}
}