use crate::CaseInsensitiveString;
use hashbrown::HashSet;
use std::hash::Hash;
use std::marker::PhantomData;
use string_interner::symbol::SymbolUsize;
use string_interner::StringInterner;
#[cfg(all(
feature = "string_interner_bucket_backend",
not(feature = "string_interner_string_backend"),
not(feature = "string_interner_buffer_backend"),
))]
type Backend = string_interner::backend::BucketBackend<SymbolUsize>;
#[cfg(all(
feature = "string_interner_string_backend",
not(feature = "string_interner_bucket_backend"),
not(feature = "string_interner_buffer_backend"),
))]
type Backend = string_interner::backend::StringBackend<SymbolUsize>;
#[cfg(all(
feature = "string_interner_buffer_backend",
not(feature = "string_interner_bucket_backend"),
not(feature = "string_interner_string_backend"),
))]
type Backend = string_interner::backend::BufferBackend<SymbolUsize>;
#[cfg(all(
not(feature = "string_interner_bucket_backend"),
not(feature = "string_interner_string_backend"),
not(feature = "string_interner_buffer_backend")
))]
type Backend = string_interner::backend::BucketBackend<SymbolUsize>;
#[cfg(all(
feature = "string_interner_bucket_backend",
feature = "string_interner_string_backend",
feature = "string_interner_buffer_backend"
))]
type Backend = string_interner::backend::BucketBackend<SymbolUsize>;
#[derive(Debug, Clone)]
pub struct ListBucket<K = CaseInsensitiveString>
where
K: Eq + Hash + AsRef<str>,
{
pub(crate) links_visited: HashSet<SymbolUsize>,
pub(crate) interner: StringInterner<Backend>,
_marker: PhantomData<K>,
}
impl<K> Default for ListBucket<K>
where
K: Eq + Hash + AsRef<str>,
{
fn default() -> Self {
Self {
links_visited: HashSet::new(),
interner: StringInterner::new(),
_marker: PhantomData,
}
}
}
impl<K> ListBucket<K>
where
K: Eq + Hash + AsRef<str>,
{
pub fn new() -> Self {
Self::default()
}
#[inline(always)]
pub fn insert(&mut self, link: K) {
let symbol = self.interner.get_or_intern(link.as_ref());
self.links_visited.insert(symbol);
}
#[inline(always)]
pub fn contains(&self, link: &K) -> bool {
if let Some(symbol) = self.interner.get(link.as_ref()) {
self.links_visited.contains(&symbol)
} else {
false
}
}
pub fn len(&self) -> usize {
self.links_visited.len()
}
pub fn drain(&mut self) -> hashbrown::hash_set::Drain<'_, SymbolUsize> {
self.links_visited.drain()
}
pub fn clear(&mut self) {
self.links_visited.clear()
}
pub fn get_links(&self) -> HashSet<K>
where
K: Hash + Clone + From<String>,
{
self.links_visited
.iter()
.filter_map(|symbol| self.interner.resolve(*symbol))
.map(|s| K::from(s.to_owned()))
.collect()
}
#[inline(always)]
pub fn extend_links(&mut self, links: &mut HashSet<K>, msg: HashSet<K>)
where
K: Clone,
{
for link in msg {
let symbol = self.interner.get_or_intern(link.as_ref());
if !self.links_visited.contains(&symbol) {
links.insert(link);
}
}
}
#[inline(always)]
pub fn extend_with_new_links(&mut self, links: &mut HashSet<K>, s: K)
where
K: Clone,
{
if let Some(symbol) = self.interner.get(s.as_ref()) {
if !self.links_visited.contains(&symbol) {
links.insert(s);
}
} else {
links.insert(s);
}
}
}