use crate::{
backend::{
Backend,
InternedStr,
},
compat::{
DefaultHashBuilder,
HashMap,
},
DefaultBackend,
DefaultSymbol,
InternalStr,
Symbol,
};
use core::{
hash::BuildHasher,
iter::FromIterator,
};
#[derive(Debug)]
pub struct StringInterner<S = DefaultSymbol, B = DefaultBackend, H = DefaultHashBuilder>
where
S: Symbol,
B: Backend<S>,
H: BuildHasher,
{
map: HashMap<InternalStr, S, H>,
backend: B,
}
impl Default for StringInterner<DefaultSymbol, DefaultBackend, DefaultHashBuilder> {
#[inline]
fn default() -> Self {
StringInterner::new()
}
}
impl<S, B, H> Clone for StringInterner<S, B, H>
where
S: Symbol,
B: Backend<S> + Clone,
for<'a> &'a B: IntoIterator<Item = (S, &'a str)>,
H: BuildHasher + Default,
{
fn clone(&self) -> Self {
let backend = self.backend.clone();
let map = backend
.into_iter()
.map(|(id, str)| (InternedStr::new(str).into(), id))
.collect::<HashMap<_, S, H>>();
Self { map, backend }
}
}
impl<S, B, H> PartialEq for StringInterner<S, B, H>
where
S: Symbol,
B: Backend<S> + PartialEq,
H: BuildHasher,
{
fn eq(&self, rhs: &Self) -> bool {
self.len() == rhs.len() && self.backend == rhs.backend
}
}
impl<S, B, H> Eq for StringInterner<S, B, H>
where
S: Symbol,
B: Backend<S> + Eq,
H: BuildHasher,
{
}
impl<S, B, H> StringInterner<S, B, H>
where
S: Symbol,
B: Backend<S>,
H: BuildHasher + Default,
{
#[inline]
pub fn new() -> Self {
Self {
map: HashMap::default(),
backend: B::default(),
}
}
#[inline]
pub fn with_capacity(cap: usize) -> Self {
Self {
map: HashMap::default(),
backend: B::with_capacity(cap),
}
}
}
impl<S, B, H> StringInterner<S, B, H>
where
S: Symbol,
B: Backend<S>,
H: BuildHasher,
{
#[inline]
pub fn with_hasher(hash_builder: H) -> Self {
StringInterner {
map: HashMap::with_hasher(hash_builder),
backend: B::default(),
}
}
#[inline]
pub fn with_capacity_and_hasher(cap: usize, hash_builder: H) -> Self {
StringInterner {
map: HashMap::with_hasher(hash_builder),
backend: B::with_capacity(cap),
}
}
#[inline]
pub fn len(&self) -> usize {
self.map.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
pub fn get<T>(&self, string: T) -> Option<S>
where
T: AsRef<str>,
{
self.map.get(string.as_ref()).copied()
}
#[inline]
pub fn get_or_intern<T>(&mut self, string: T) -> S
where
T: AsRef<str>,
{
let str = string.as_ref();
self.map.get(str).copied().unwrap_or_else(|| unsafe {
let (interned_str, symbol) = self.backend.intern(str);
self.map.insert(interned_str.into(), symbol);
symbol
})
}
#[inline]
pub fn resolve(&self, symbol: S) -> Option<&str> {
self.backend.resolve(symbol)
}
}
unsafe impl<S, B, H> Send for StringInterner<S, B, H>
where
S: Symbol + Send,
B: Backend<S> + Send,
H: BuildHasher,
{
}
unsafe impl<S, B, H> Sync for StringInterner<S, B, H>
where
S: Symbol + Sync,
B: Backend<S> + Sync,
H: BuildHasher,
{
}
impl<'a, S, B, H, T> FromIterator<T> for StringInterner<S, B, H>
where
S: Symbol,
B: Backend<S>,
H: BuildHasher + Default,
T: AsRef<str>,
{
fn from_iter<I>(iter: I) -> Self
where
I: IntoIterator<Item = T>,
{
let iter = iter.into_iter();
let (capacity, _) = iter.size_hint();
let mut interner = Self::with_capacity(capacity);
interner.extend(iter);
interner
}
}
impl<'a, S, B, H, T> Extend<T> for StringInterner<S, B, H>
where
S: Symbol,
B: Backend<S>,
H: BuildHasher,
T: AsRef<str>,
{
#[inline]
fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = T>,
{
for s in iter {
self.get_or_intern(s.as_ref());
}
}
}
impl<'a, S, B, H> IntoIterator for &'a StringInterner<S, B, H>
where
S: Symbol,
B: Backend<S>,
&'a B: IntoIterator<Item = (S, &'a str)>,
H: BuildHasher,
{
type Item = (S, &'a str);
type IntoIter = <&'a B as IntoIterator>::IntoIter;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.backend.into_iter()
}
}