use std::{
any::{Any, TypeId},
collections::HashMap,
hash::Hash,
};
use once_cell::sync::Lazy;
use parking_lot::{RwLock, RwLockUpgradableReadGuard};
use crate::{HashInterner, OrdInterner};
static HASH_INTERNERS: Lazy<RwLock<HashInternerPool>> = Lazy::new(Default::default);
pub struct HashInternerPool {
type_map: HashMap<TypeId, Box<dyn Any + Send + Sync + 'static>>,
}
impl Default for HashInternerPool {
fn default() -> Self {
Self::new()
}
}
impl HashInternerPool {
pub fn new() -> Self {
Self {
type_map: HashMap::new(),
}
}
pub fn get<T>(&self) -> Option<HashInterner<T>>
where
T: Eq + Hash + Send + Sync + Any + ?Sized + 'static,
{
self.type_map
.get(&TypeId::of::<T>())
.map(|v| v.downcast_ref::<HashInterner<T>>().unwrap().clone())
}
pub fn get_or_create<T>(&mut self) -> HashInterner<T>
where
T: Eq + Hash + Send + Sync + Any + ?Sized + 'static,
{
self.get::<T>().unwrap_or_else(|| {
let ret = HashInterner::new();
self.type_map
.insert(TypeId::of::<T>(), Box::new(ret.clone()));
ret
})
}
}
pub fn hash_interner<T>() -> HashInterner<T>
where
T: Eq + Hash + Send + Sync + Any + ?Sized + 'static,
{
let map = HASH_INTERNERS.upgradable_read();
if let Some(interner) = map.get::<T>() {
return interner;
}
let mut map = RwLockUpgradableReadGuard::upgrade(map);
map.get_or_create::<T>()
}
static ORD_INTERNERS: Lazy<RwLock<OrdInternerPool>> = Lazy::new(Default::default);
pub struct OrdInternerPool {
type_map: HashMap<TypeId, Box<dyn Any + Send + Sync + 'static>>,
}
impl Default for OrdInternerPool {
fn default() -> Self {
Self::new()
}
}
impl OrdInternerPool {
pub fn new() -> Self {
Self {
type_map: HashMap::new(),
}
}
pub fn get<T>(&self) -> Option<OrdInterner<T>>
where
T: Ord + Send + Sync + Any + ?Sized + 'static,
{
self.type_map
.get(&TypeId::of::<T>())
.map(|v| v.downcast_ref::<OrdInterner<T>>().unwrap().clone())
}
pub fn get_or_create<T>(&mut self) -> OrdInterner<T>
where
T: Ord + Send + Sync + Any + ?Sized + 'static,
{
self.get::<T>().unwrap_or_else(|| {
let ret = OrdInterner::new();
self.type_map
.insert(TypeId::of::<T>(), Box::new(ret.clone()));
ret
})
}
}
pub fn ord_interner<T>() -> OrdInterner<T>
where
T: Ord + Send + Sync + Any + ?Sized + 'static,
{
let map = ORD_INTERNERS.upgradable_read();
if let Some(interner) = map.get::<T>() {
return interner;
}
let mut map = RwLockUpgradableReadGuard::upgrade(map);
map.get_or_create::<T>()
}