Add docs to bootstrap:src:utils:cache
This commit is contained in:
parent
80c091958f
commit
8a0a4df0c6
1 changed files with 43 additions and 0 deletions
|
|
@ -1,3 +1,17 @@
|
|||
//! This module helps you efficiently store and retrieve values using interning.
|
||||
//!
|
||||
//! Interning is a neat trick that keeps only one copy of identical values, saving memory
|
||||
//! and making comparisons super fast. Here, we provide the `Interned<T>` struct and the `Internable` trait
|
||||
//! to make interning easy for different data types.
|
||||
//!
|
||||
//! The `Interner` struct handles caching for common types like `String`, `PathBuf`, and `Vec<String>`,
|
||||
//! while the `Cache` struct acts as a write-once storage for linking computation steps with their results.
|
||||
//!
|
||||
//! # Thread Safety
|
||||
//!
|
||||
//! We use `Mutex` to make sure interning and retrieval are thread-safe. But keep in mind—once a value is
|
||||
//! interned, it sticks around for the entire lifetime of the program.
|
||||
|
||||
use std::any::{Any, TypeId};
|
||||
use std::borrow::Borrow;
|
||||
use std::cell::RefCell;
|
||||
|
|
@ -12,6 +26,9 @@ use std::{fmt, mem};
|
|||
|
||||
use crate::core::builder::Step;
|
||||
|
||||
/// Represents an interned value of type `T`, allowing for efficient comparisons and retrieval.
|
||||
///
|
||||
/// This struct stores a unique index referencing the interned value within an internal cache.
|
||||
pub struct Interned<T>(usize, PhantomData<*const T>);
|
||||
|
||||
impl<T: Internable + Default> Default for Interned<T> {
|
||||
|
|
@ -111,6 +128,10 @@ impl<T: Internable + Ord> Ord for Interned<T> {
|
|||
}
|
||||
}
|
||||
|
||||
/// A structure for managing the interning of values of type `T`.
|
||||
///
|
||||
/// `TyIntern<T>` maintains a mapping between values and their interned representations,
|
||||
/// ensuring that duplicate values are not stored multiple times.
|
||||
struct TyIntern<T: Clone + Eq> {
|
||||
items: Vec<T>,
|
||||
set: HashMap<T, Interned<T>>,
|
||||
|
|
@ -123,6 +144,9 @@ impl<T: Hash + Clone + Eq> Default for TyIntern<T> {
|
|||
}
|
||||
|
||||
impl<T: Hash + Clone + Eq> TyIntern<T> {
|
||||
/// Interns a borrowed value, ensuring it is stored uniquely.
|
||||
///
|
||||
/// If the value has been previously interned, the same `Interned<T>` instance is returned.
|
||||
fn intern_borrow<B>(&mut self, item: &B) -> Interned<T>
|
||||
where
|
||||
B: Eq + Hash + ToOwned<Owned = T> + ?Sized,
|
||||
|
|
@ -138,6 +162,9 @@ impl<T: Hash + Clone + Eq> TyIntern<T> {
|
|||
interned
|
||||
}
|
||||
|
||||
/// Interns an owned value, storing it uniquely.
|
||||
///
|
||||
/// If the value has been previously interned, the existing `Interned<T>` is returned.
|
||||
fn intern(&mut self, item: T) -> Interned<T> {
|
||||
if let Some(i) = self.set.get(&item) {
|
||||
return *i;
|
||||
|
|
@ -148,11 +175,16 @@ impl<T: Hash + Clone + Eq> TyIntern<T> {
|
|||
interned
|
||||
}
|
||||
|
||||
/// Retrieves a reference to the interned value associated with the given `Interned<T>` instance.
|
||||
fn get(&self, i: Interned<T>) -> &T {
|
||||
&self.items[i.0]
|
||||
}
|
||||
}
|
||||
|
||||
/// A global interner for managing interned values of common types.
|
||||
///
|
||||
/// This structure maintains caches for `String`, `PathBuf`, and `Vec<String>`, ensuring efficient storage
|
||||
/// and retrieval of frequently used values.
|
||||
#[derive(Default)]
|
||||
pub struct Interner {
|
||||
strs: Mutex<TyIntern<String>>,
|
||||
|
|
@ -160,6 +192,10 @@ pub struct Interner {
|
|||
lists: Mutex<TyIntern<Vec<String>>>,
|
||||
}
|
||||
|
||||
/// Defines the behavior required for a type to be internable.
|
||||
///
|
||||
/// Types implementing this trait must provide access to a static cache and define an `intern` method
|
||||
/// that ensures values are stored uniquely.
|
||||
trait Internable: Clone + Eq + Hash + 'static {
|
||||
fn intern_cache() -> &'static Mutex<TyIntern<Self>>;
|
||||
|
||||
|
|
@ -187,11 +223,15 @@ impl Internable for Vec<String> {
|
|||
}
|
||||
|
||||
impl Interner {
|
||||
/// Interns a string reference, ensuring it is stored uniquely.
|
||||
///
|
||||
/// If the string has been previously interned, the same `Interned<String>` instance is returned.
|
||||
pub fn intern_str(&self, s: &str) -> Interned<String> {
|
||||
self.strs.lock().unwrap().intern_borrow(s)
|
||||
}
|
||||
}
|
||||
|
||||
/// A global instance of `Interner` that caches common interned values.
|
||||
pub static INTERNER: LazyLock<Interner> = LazyLock::new(Interner::default);
|
||||
|
||||
/// This is essentially a `HashMap` which allows storing any type in its input and
|
||||
|
|
@ -209,10 +249,12 @@ pub struct Cache(
|
|||
);
|
||||
|
||||
impl Cache {
|
||||
/// Creates a new empty cache.
|
||||
pub fn new() -> Cache {
|
||||
Cache(RefCell::new(HashMap::new()))
|
||||
}
|
||||
|
||||
/// Stores the result of a computation step in the cache.
|
||||
pub fn put<S: Step>(&self, step: S, value: S::Output) {
|
||||
let mut cache = self.0.borrow_mut();
|
||||
let type_id = TypeId::of::<S>();
|
||||
|
|
@ -225,6 +267,7 @@ impl Cache {
|
|||
stepcache.insert(step, value);
|
||||
}
|
||||
|
||||
/// Retrieves a cached result for the given step, if available.
|
||||
pub fn get<S: Step>(&self, step: &S) -> Option<S::Output> {
|
||||
let mut cache = self.0.borrow_mut();
|
||||
let type_id = TypeId::of::<S>();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue