use parking_lot::Mutex;
use crate::ornaments::GetHash;
use crate::hash_str::HashStr;
use crate::cache::{HashStrHost,HashStrCache,Presence};
const BIN_SHIFT: usize = 6;
const NUM_BINS: usize = 1 << BIN_SHIFT;
const TOP_SHIFT: usize =
8 * core::mem::size_of::<usize>() - BIN_SHIFT;
#[repr(transparent)]
pub struct Bins<'host>([Mutex<HostCache<'host>>; NUM_BINS]);
struct HostCache<'host>{
host:HashStrHost,
cache:HashStrCache<'host>,
}
lazy_static::lazy_static!{
static ref STRING_CACHE:Bins<'static> =
Bins(core::array::from_fn(|_|Mutex::new(
HostCache{
host:HashStrHost::new(),
cache:HashStrCache::new()
}
)));
}
#[inline]
pub fn get_cache()->&'static Bins<'static>{
&STRING_CACHE
}
#[doc(hidden)]
pub unsafe fn _clear_cache(){
for bin in &STRING_CACHE.0{
let bin=&mut*bin.lock();
bin.cache.clear();
bin.host.clear();
}
}
#[inline]
fn whichbin(hash: u64) -> usize {
((hash >> TOP_SHIFT as u64) % NUM_BINS as u64) as usize
}
impl<'host> Bins<'host>{
#[inline]
pub fn get(&self,index:impl GetHash+AsRef<str>)->Option<&'host HashStr>{
let hash=index.get_hash();
self.0[whichbin(hash)].lock().cache.presence_str_with_hash(hash,index.as_ref()).get()
}
#[inline]
pub fn presence<'a>(&self,index:impl GetHash+Into<&'a str>)->Presence<'a,&'host HashStr>{
let hash=index.get_hash();
self.0[whichbin(hash)].lock().cache.presence_str_with_hash(hash,index.into())
}
#[inline]
pub fn cache(&self,hash_str:&'host HashStr)->&'host HashStr{
let hash=hash_str.get_hash();
self.0[whichbin(hash)].lock().cache.cache(hash_str)
}
#[inline]
pub fn intern(&self,index:impl GetHash+AsRef<str>)->&'host HashStr{
self.intern_str_with_hash(index.get_hash(),index.as_ref())
}
#[inline]
pub(crate) fn intern_str_with_hash(&self,hash:u64,str:&str)->&'host HashStr{
let HostCache{cache,host}=&mut*self.0[whichbin(hash)].lock();
cache.intern_str_with_hash(||{
let ptr=host.alloc_str_with_hash(hash,str) as *const HashStr;
unsafe{&*ptr}
},hash,str)
}
}
macro_rules! impl_from_borrowed{
($ty:ty)=>{
impl From<$ty> for &'static HashStr{
fn from(value:$ty)->Self{
STRING_CACHE.intern(value)
}
}
};
}
macro_rules! impl_from_owned{
($ty:ty)=>{
impl From<$ty> for &'static HashStr{
fn from(value:$ty)->Self{
STRING_CACHE.intern(&value)
}
}
};
}
impl_from_borrowed!(&str);
impl_from_owned!(Box<str>);
impl_from_borrowed!(&Box<str>);
impl_from_owned!(String);
impl_from_borrowed!(&String);
use std::borrow::Cow;
impl_from_owned!(Cow<'_,str>);
impl_from_borrowed!(&Cow<'_,str>);