use std::collections::HashMap;
use std::sync::atomic::{AtomicU32, Ordering};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct Symbol(u32);
impl Symbol {
#[allow(dead_code)]
pub(crate) fn new(id: u32) -> Self {
Symbol(id)
}
pub fn id(self) -> u32 {
self.0
}
}
#[derive(Debug, Default, Clone)]
pub struct SymbolTable {
strings_to_ids: HashMap<String, u32>,
ids_to_strings: Vec<String>,
}
impl SymbolTable {
pub fn new() -> Self {
Self::default()
}
pub fn intern(&mut self, s: &str) -> Symbol {
if let Some(&id) = self.strings_to_ids.get(s) {
return Symbol(id);
}
let id = self.ids_to_strings.len() as u32;
self.strings_to_ids.insert(s.to_string(), id);
self.ids_to_strings.push(s.to_string());
Symbol(id)
}
pub fn resolve(&self, sym: Symbol) -> Option<&str> {
self.ids_to_strings.get(sym.0 as usize).map(|s| s.as_str())
}
pub fn len(&self) -> usize {
self.ids_to_strings.len()
}
pub fn is_empty(&self) -> bool {
self.ids_to_strings.is_empty()
}
}
static NEXT_HIR_ID: AtomicU32 = AtomicU32::new(0);
#[cfg(test)]
pub fn reset_hir_id_counter() {
NEXT_HIR_ID.store(0, Ordering::SeqCst);
}
impl super::span::HirId {
pub fn new() -> Self {
let id = NEXT_HIR_ID.fetch_add(1, Ordering::SeqCst);
Self(id)
}
pub fn id(self) -> u32 {
self.0
}
}
impl Default for super::span::HirId {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_symbol_interning() {
let mut table = SymbolTable::new();
let s1 = table.intern("foo");
let s2 = table.intern("bar");
let s3 = table.intern("foo");
assert_eq!(s1, s3);
assert_ne!(s1, s2);
assert_eq!(table.resolve(s1), Some("foo"));
assert_eq!(table.resolve(s2), Some("bar"));
}
#[test]
fn test_symbol_table_len() {
let mut table = SymbolTable::new();
assert!(table.is_empty());
table.intern("a");
table.intern("b");
table.intern("a");
assert_eq!(table.len(), 2);
}
}