mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-02 18:28:12 +08:00
Invalidate Caches based on the received input (#1067)
* Invalidate Caches based on the received input * Add comments * Fix missing *
This commit is contained in:
committed by
Keavon Chambers
parent
ccb698ffa8
commit
4ea3802df1
Generated
+7
@@ -359,6 +359,12 @@ dependencies = [
|
|||||||
"dyn-any",
|
"dyn-any",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "boxcar"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "38c99613cb3cd7429889a08dfcf651721ca971c86afa30798461f8eee994de47"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "brotli"
|
name = "brotli"
|
||||||
version = "3.3.4"
|
version = "3.3.4"
|
||||||
@@ -1663,6 +1669,7 @@ dependencies = [
|
|||||||
"autoquant",
|
"autoquant",
|
||||||
"bezier-rs",
|
"bezier-rs",
|
||||||
"borrow_stack",
|
"borrow_stack",
|
||||||
|
"boxcar",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"compilation-client",
|
"compilation-client",
|
||||||
"dyn-any",
|
"dyn-any",
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ quantization = ["autoquant"]
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
autoquant = { git = "https://github.com/truedoctor/autoquant", optional = true, features = ["fitting"] }
|
autoquant = { git = "https://github.com/truedoctor/autoquant", optional = true, features = ["fitting"] }
|
||||||
graphene-core = {path = "../gcore", features = ["async", "std" ], default-features = false}
|
graphene-core = {path = "../gcore", features = ["async", "std", "serde" ], default-features = false}
|
||||||
borrow_stack = {path = "../borrow_stack"}
|
borrow_stack = {path = "../borrow_stack"}
|
||||||
dyn-any = {path = "../../libraries/dyn-any", features = ["derive"]}
|
dyn-any = {path = "../../libraries/dyn-any", features = ["derive"]}
|
||||||
graph-craft = {path = "../graph-craft"}
|
graph-craft = {path = "../graph-craft"}
|
||||||
@@ -38,12 +38,13 @@ image = "*"
|
|||||||
dyn-clone = "1.0"
|
dyn-clone = "1.0"
|
||||||
|
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
bezier-rs = { path = "../../libraries/bezier-rs" }
|
bezier-rs = { path = "../../libraries/bezier-rs" , features = ["serde"] }
|
||||||
kurbo = { git = "https://github.com/linebender/kurbo.git", features = [
|
kurbo = { git = "https://github.com/linebender/kurbo.git", features = [
|
||||||
"serde",
|
"serde",
|
||||||
] }
|
] }
|
||||||
glam = { version = "0.22", features = ["serde"] }
|
glam = { version = "0.22", features = ["serde"] }
|
||||||
node-macro = { path="../node-macro" }
|
node-macro = { path="../node-macro" }
|
||||||
|
boxcar = "0.1.0"
|
||||||
|
|
||||||
[dependencies.serde]
|
[dependencies.serde]
|
||||||
version = "1.0"
|
version = "1.0"
|
||||||
|
|||||||
+43
-16
@@ -1,50 +1,77 @@
|
|||||||
|
use std::collections::hash_map::DefaultHasher;
|
||||||
|
use std::hash::{Hash, Hasher};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use graphene_core::Node;
|
use graphene_core::Node;
|
||||||
use once_cell::sync::OnceCell;
|
|
||||||
|
|
||||||
/// Caches the output of a given Node and acts as a proxy
|
/// Caches the output of a given Node and acts as a proxy
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct CacheNode<T> {
|
pub struct CacheNode<T> {
|
||||||
cache: OnceCell<T>,
|
// We have to use an append only data structure to make sure the references
|
||||||
|
// to the cache entries are always valid
|
||||||
|
cache: boxcar::Vec<(u64, T)>,
|
||||||
}
|
}
|
||||||
impl<'i, T: 'i> Node<'i, T> for CacheNode<T> {
|
impl<'i, T: 'i + Hash> Node<'i, T> for CacheNode<T> {
|
||||||
type Output = &'i T;
|
type Output = &'i T;
|
||||||
fn eval<'s: 'i>(&'s self, input: T) -> Self::Output {
|
fn eval<'s: 'i>(&'s self, input: T) -> Self::Output {
|
||||||
self.cache.get_or_init(|| {
|
let mut hasher = DefaultHasher::new();
|
||||||
trace!("Creating new cache node");
|
input.hash(&mut hasher);
|
||||||
input
|
let hash = hasher.finish();
|
||||||
})
|
|
||||||
|
if let Some((_, cached_value)) = self.cache.iter().find(|(h, _)| *h == hash) {
|
||||||
|
return cached_value;
|
||||||
|
} else {
|
||||||
|
trace!("Cache miss");
|
||||||
|
let index = self.cache.push((hash, input));
|
||||||
|
return &self.cache[index].1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> CacheNode<T> {
|
impl<T> CacheNode<T> {
|
||||||
pub const fn new() -> CacheNode<T> {
|
pub fn new() -> CacheNode<T> {
|
||||||
CacheNode { cache: OnceCell::new() }
|
CacheNode { cache: boxcar::Vec::new() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Caches the output of a given Node and acts as a proxy
|
/// Caches the output of a given Node and acts as a proxy
|
||||||
|
/// It provides two modes of operation, it can either be set
|
||||||
|
/// when calling the node with a `Some<T>` variant or the last
|
||||||
|
/// value that was added is returned when calling it with `None`
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||||
pub struct LetNode<T> {
|
pub struct LetNode<T> {
|
||||||
cache: OnceCell<T>,
|
// We have to use an append only data structure to make sure the references
|
||||||
|
// to the cache entries are always valid
|
||||||
|
// TODO: We only ever access the last value so there is not really a reason for us
|
||||||
|
// to store the previous entries. This should be reworked in the future
|
||||||
|
cache: boxcar::Vec<(u64, T)>,
|
||||||
}
|
}
|
||||||
impl<'i, T: 'i> Node<'i, Option<T>> for LetNode<T> {
|
impl<'i, T: 'i + Hash> Node<'i, Option<T>> for LetNode<T> {
|
||||||
type Output = &'i T;
|
type Output = &'i T;
|
||||||
fn eval<'s: 'i>(&'s self, input: Option<T>) -> Self::Output {
|
fn eval<'s: 'i>(&'s self, input: Option<T>) -> Self::Output {
|
||||||
match input {
|
match input {
|
||||||
Some(input) => {
|
Some(input) => {
|
||||||
self.cache.set(input).unwrap_or_else(|_| error!("Let node was set twice but is not mutable"));
|
let mut hasher = DefaultHasher::new();
|
||||||
self.cache.get().unwrap()
|
input.hash(&mut hasher);
|
||||||
|
let hash = hasher.finish();
|
||||||
|
|
||||||
|
if let Some((cached_hash, cached_value)) = self.cache.iter().last() {
|
||||||
|
if hash == *cached_hash {
|
||||||
|
return cached_value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trace!("Cache miss");
|
||||||
|
let index = self.cache.push((hash, input));
|
||||||
|
return &self.cache[index].1;
|
||||||
}
|
}
|
||||||
None => self.cache.get().expect("Let node was not initialized"),
|
None => &self.cache.iter().last().expect("Let node was not initialized").1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> LetNode<T> {
|
impl<T> LetNode<T> {
|
||||||
pub const fn new() -> LetNode<T> {
|
pub fn new() -> LetNode<T> {
|
||||||
LetNode { cache: OnceCell::new() }
|
LetNode { cache: boxcar::Vec::new() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user