use std::collections::hash_map::HashMap;
use std::hash::Hash;
use uuid::Uuid;
use crate::database::id::*;
use crate::url::UrlWithoutFragment;
pub type UrlCache = IdCache<UrlWithoutFragment, UrlId>;
pub type EntityGenerationUuidCache = IdCache<Uuid, EntityGenerationId>;
pub struct IdCache<
T: Eq + Hash + Clone,
I: NumericDatabseId + Eq + Hash + Clone + Copy
> {
data_to_id: HashMap<T, I>,
id_to_data: HashMap<I, T>,
queue: [Option<I>; 2048],
offset: usize
}
impl<T, I> IdCache<T, I>
where
T: Eq + Hash + Clone,
I: NumericDatabseId + Eq + Hash + Clone + Copy
{
pub fn new() -> Self {
Self {
data_to_id: HashMap::with_capacity(2048),
id_to_data: HashMap::with_capacity(2048),
offset: 0,
queue: [None; 2048],
}
}
#[inline(always)]
pub fn bump_offset(&mut self) {
self.offset = (self.offset + 1) & (2048-1);
}
pub fn push(&mut self, id: I, data: &T) {
if self.id_to_data.insert(id, data.clone()).is_none() {
self.data_to_id.insert(data.clone(), id);
self.queue[self.offset] = Some(id);
self.bump_offset();
} else {
return;
}
if self.queue[self.offset].is_none() { return; }
let mut c: usize = 0;
while c < 1024 {
if let Some(id) = self.queue[self.offset] {
self.remove_by_id(id);
self.queue[self.offset] = None;
self.bump_offset();
c += 1;
} else {
break; }
}
}
fn remove_by_id(&mut self, id: I) {
if let Some(data) = self.id_to_data.get(&id) {
self.data_to_id.remove(data);
self.id_to_data.remove(&id);
}
}
pub fn get_id(&self, data: &T) -> Option<I> {
return self.data_to_id.get(data).copied();
}
pub fn get_data(&self, id: I) -> Option<T> {
return self.id_to_data.get(&id).cloned();
}
}
impl<T, I> Default for IdCache<T, I>
where
T: Eq + Hash + Clone,
I: NumericDatabseId + Eq + Hash + Clone + Copy
{
fn default() -> Self {
Self::new()
}
}
impl UrlCache {
pub fn get_url(&self, id: UrlId) -> Option<UrlWithoutFragment> {
self.get_data(id)
}
}
impl EntityGenerationUuidCache {
pub fn get_uuid(&self, id: EntityGenerationId) -> Option<Uuid> {
self.get_data(id)
}
}