use std::hash::{Hash, Hasher};
use hashbrown::{Equivalent, HashMap};
struct CacheEntry<T> {
resource: T,
generation: usize,
}
pub(crate) struct GenerationalCache<K, T>
where
K: Eq + Hash,
{
resources: HashMap<K, CacheEntry<T>>,
current_generation: usize,
max_age: usize,
}
impl<K, T> Default for GenerationalCache<K, T>
where
K: Eq + Hash,
{
fn default() -> Self {
Self {
resources: Default::default(),
current_generation: 0,
max_age: 2,
}
}
}
impl<K, T> GenerationalCache<K, T>
where
K: Eq + Hash,
{
pub(crate) fn new(max_age: usize) -> Self {
GenerationalCache {
resources: HashMap::default(),
current_generation: 0,
max_age,
}
}
pub(crate) fn next_gen(&mut self) {
self.resources.retain(|_, entry| {
self.current_generation.wrapping_sub(entry.generation) < self.max_age
});
self.current_generation = self.current_generation.wrapping_add(1);
}
#[allow(unused)]
pub(crate) fn contains_key<Q>(&mut self, key: &Q) -> bool
where
Q: Hash + Equivalent<K> + ?Sized,
{
self.resources.contains_key(key)
}
pub(crate) fn hit<Q>(&mut self, key: &Q) -> Option<&T>
where
Q: Hash + Equivalent<K> + ?Sized,
{
if let Some(entry) = self.resources.get_mut(key) {
entry.generation = self.current_generation;
Some(&entry.resource)
} else {
None
}
}
pub(crate) fn insert(&mut self, key: K, resource: T) {
let entry = CacheEntry {
resource,
generation: self.current_generation,
};
self.resources.insert(key, entry);
}
}
#[derive(PartialEq, Eq)]
pub(crate) struct NormalizedTypefaceCacheKey {
pub(crate) typeface_id: u64,
pub(crate) typeface_index: u32,
pub(crate) normalized_coords: Vec<i16>,
}
impl Hash for NormalizedTypefaceCacheKey {
fn hash<H: Hasher>(&self, state: &mut H) {
self.typeface_id.hash(state);
self.typeface_index.hash(state);
for &coord in &self.normalized_coords {
coord.hash(state);
}
}
}
pub(crate) struct NormalizedTypefaceCacheKeyBorrowed<'a> {
pub(crate) typeface_id: u64,
pub(crate) typeface_index: u32,
pub(crate) normalized_coords: &'a [i16],
}
impl<'a> Hash for NormalizedTypefaceCacheKeyBorrowed<'a> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.typeface_id.hash(state);
self.typeface_index.hash(state);
for &coord in self.normalized_coords {
coord.hash(state);
}
}
}
impl Equivalent<NormalizedTypefaceCacheKey> for NormalizedTypefaceCacheKeyBorrowed<'_> {
fn equivalent(&self, key: &NormalizedTypefaceCacheKey) -> bool {
self.typeface_id == key.typeface_id
&& self.typeface_index == key.typeface_index
&& self.normalized_coords == key.normalized_coords
}
}
pub(crate) struct FontCacheKeyBorrowed<'a> {
pub(crate) typeface_id: u64,
pub(crate) typeface_index: u32,
pub(crate) normalized_coords: &'a [i16],
pub(crate) font_size: u32,
pub(crate) hint: bool,
}
impl<'a> Hash for FontCacheKeyBorrowed<'a> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.typeface_id.hash(state);
self.typeface_index.hash(state);
for &coord in self.normalized_coords {
coord.hash(state);
}
self.font_size.hash(state);
self.hint.hash(state);
}
}
#[derive(PartialEq, Eq)]
pub(crate) struct FontCacheKey {
pub(crate) typeface_id: u64,
pub(crate) typeface_index: u32,
pub(crate) normalized_coords: Vec<i16>,
pub(crate) font_size: u32,
pub(crate) hint: bool,
}
impl Hash for FontCacheKey {
fn hash<H: Hasher>(&self, state: &mut H) {
self.typeface_id.hash(state);
self.typeface_index.hash(state);
for &coord in &self.normalized_coords {
coord.hash(state);
}
self.font_size.hash(state);
self.hint.hash(state);
}
}
impl Equivalent<FontCacheKey> for FontCacheKeyBorrowed<'_> {
fn equivalent(&self, key: &FontCacheKey) -> bool {
self.typeface_id == key.typeface_id
&& self.typeface_index == key.typeface_index
&& self.font_size == key.font_size
&& self.hint == key.hint
&& self.normalized_coords == key.normalized_coords
}
}