Skip to content

Commit

Permalink
Move egui::util::cache to egui::cache, and improve docstrings
Browse files Browse the repository at this point in the history
  • Loading branch information
emilk committed Dec 3, 2024
1 parent a9c76ba commit d97b225
Show file tree
Hide file tree
Showing 8 changed files with 108 additions and 86 deletions.
68 changes: 68 additions & 0 deletions crates/egui/src/cache/cache_storage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
use super::CacheTrait;

/// A typemap of many caches, all implemented with [`CacheTrait`].
///
/// You can access egui's caches via [`crate::Memory::caches`],
/// found with [`crate::Context::memory_mut`].
///
/// ```
/// use egui::cache::{CacheStorage, ComputerMut, FrameCache};
///
/// #[derive(Default)]
/// struct CharCounter {}
/// impl ComputerMut<&str, usize> for CharCounter {
/// fn compute(&mut self, s: &str) -> usize {
/// s.chars().count()
/// }
/// }
/// type CharCountCache<'a> = FrameCache<usize, CharCounter>;
///
/// # let mut cache_storage = CacheStorage::default();
/// let mut cache = cache_storage.cache::<CharCountCache<'_>>();
/// assert_eq!(cache.get("hello"), 5);
/// ```
#[derive(Default)]
pub struct CacheStorage {
caches: ahash::HashMap<std::any::TypeId, Box<dyn CacheTrait>>,
}

impl CacheStorage {
pub fn cache<Cache: CacheTrait + Default>(&mut self) -> &mut Cache {
self.caches
.entry(std::any::TypeId::of::<Cache>())
.or_insert_with(|| Box::<Cache>::default())
.as_any_mut()
.downcast_mut::<Cache>()
.unwrap()
}

/// Total number of cached values
fn num_values(&self) -> usize {
self.caches.values().map(|cache| cache.len()).sum()
}

/// Call once per frame to evict cache.
pub fn update(&mut self) {
for cache in self.caches.values_mut() {
cache.update();
}
}
}

impl Clone for CacheStorage {
fn clone(&self) -> Self {
// We return an empty cache that can be filled in again.
Self::default()
}
}

impl std::fmt::Debug for CacheStorage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"FrameCacheStorage[{} caches with {} elements]",
self.caches.len(),
self.num_values()
)
}
}
11 changes: 11 additions & 0 deletions crates/egui/src/cache/cache_trait.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/// A cache, storing some value for some length of time.
#[allow(clippy::len_without_is_empty)]
pub trait CacheTrait: 'static + Send + Sync {
/// Call once per frame to evict cache.
fn update(&mut self);

/// Number of values currently in the cache.
fn len(&self) -> usize;

fn as_any_mut(&mut self) -> &mut dyn std::any::Any;
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
//! Computing the same thing each frame can be expensive,
//! so often you want to save the result from the previous frame and reuse it.
//!
//! Enter [`FrameCache`]: it caches the results of a computation for one frame.
//! If it is still used next frame, it is not recomputed.
//! If it is not used next frame, it is evicted from the cache to save memory.
use super::CacheTrait;

/// Something that does an expensive computation that we want to cache
/// to save us from recomputing it each frame.
Expand Down Expand Up @@ -74,17 +69,6 @@ impl<Value, Computer> FrameCache<Value, Computer> {
}
}

#[allow(clippy::len_without_is_empty)]
pub trait CacheTrait: 'static + Send + Sync {
/// Call once per frame to evict cache.
fn update(&mut self);

/// Number of values currently in the cache.
fn len(&self) -> usize;

fn as_any_mut(&mut self) -> &mut dyn std::any::Any;
}

impl<Value: 'static + Send + Sync, Computer: 'static + Send + Sync> CacheTrait
for FrameCache<Value, Computer>
{
Expand All @@ -100,65 +84,3 @@ impl<Value: 'static + Send + Sync, Computer: 'static + Send + Sync> CacheTrait
self
}
}

/// ```
/// use egui::util::cache::{CacheStorage, ComputerMut, FrameCache};
///
/// #[derive(Default)]
/// struct CharCounter {}
/// impl ComputerMut<&str, usize> for CharCounter {
/// fn compute(&mut self, s: &str) -> usize {
/// s.chars().count()
/// }
/// }
/// type CharCountCache<'a> = FrameCache<usize, CharCounter>;
///
/// # let mut cache_storage = CacheStorage::default();
/// let mut cache = cache_storage.cache::<CharCountCache<'_>>();
/// assert_eq!(cache.get("hello"), 5);
/// ```
#[derive(Default)]
pub struct CacheStorage {
caches: ahash::HashMap<std::any::TypeId, Box<dyn CacheTrait>>,
}

impl CacheStorage {
pub fn cache<FrameCache: CacheTrait + Default>(&mut self) -> &mut FrameCache {
self.caches
.entry(std::any::TypeId::of::<FrameCache>())
.or_insert_with(|| Box::<FrameCache>::default())
.as_any_mut()
.downcast_mut::<FrameCache>()
.unwrap()
}

/// Total number of cached values
fn num_values(&self) -> usize {
self.caches.values().map(|cache| cache.len()).sum()
}

/// Call once per frame to evict cache.
pub fn update(&mut self) {
for cache in self.caches.values_mut() {
cache.update();
}
}
}

impl Clone for CacheStorage {
fn clone(&self) -> Self {
// We return an empty cache that can be filled in again.
Self::default()
}
}

impl std::fmt::Debug for CacheStorage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"FrameCacheStorage[{} caches with {} elements]",
self.caches.len(),
self.num_values()
)
}
}
19 changes: 19 additions & 0 deletions crates/egui/src/cache/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//! Caches for preventing the same value from being recomputed every frame.
//!
//! Computing the same thing each frame can be expensive,
//! so often you want to save the result from the previous frame and reuse it.
//!
//! Enter [`FrameCache`]: it caches the results of a computation for one frame.
//! If it is still used next frame, it is not recomputed.
//! If it is not used next frame, it is evicted from the cache to save memory.
//!
//! You can access egui's caches via [`crate::Memory::caches`],
//! found with [`crate::Context::memory_mut`].
mod cache_storage;
mod cache_trait;
mod frame_cache;

pub use cache_storage::CacheStorage;
pub use cache_trait::CacheTrait;
pub use frame_cache::{ComputerMut, FrameCache};
1 change: 1 addition & 0 deletions crates/egui/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,7 @@
#![allow(clippy::manual_range_contains)]

mod animation_manager;
pub mod cache;
pub mod containers;
mod context;
mod data;
Expand Down
4 changes: 2 additions & 2 deletions crates/egui/src/memory/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ pub struct Memory {
/// so as not to lock the UI thread.
///
/// ```
/// use egui::util::cache::{ComputerMut, FrameCache};
/// use egui::cache::{ComputerMut, FrameCache};
///
/// #[derive(Default)]
/// struct CharCounter {}
Expand All @@ -72,7 +72,7 @@ pub struct Memory {
/// });
/// ```
#[cfg_attr(feature = "persistence", serde(skip))]
pub caches: crate::util::cache::CacheStorage,
pub caches: crate::cache::CacheStorage,

// ------------------------------------------
/// new fonts that will be applied at the start of the next frame
Expand Down
5 changes: 4 additions & 1 deletion crates/egui/src/util/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
//! Miscellaneous tools used by the rest of egui.
pub mod cache;
pub(crate) mod fixed_cache;
pub mod id_type_map;
pub mod undoer;
Expand All @@ -9,3 +8,7 @@ pub use id_type_map::IdTypeMap;

pub use epaint::emath::History;
pub use epaint::util::{hash, hash_with};

/// Deprecated alias for [`egui::cache`].
#[deprecated = "Use egui::cache instead"]
pub use crate::cache;
6 changes: 2 additions & 4 deletions crates/egui_extras/src/syntax_highlighting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,7 @@ pub fn highlight(
// performing it at a separate thread (ctx, ctx.style()) can be used and when ui is available
// (ui.ctx(), ui.style()) can be used

impl egui::util::cache::ComputerMut<(&egui::FontId, &CodeTheme, &str, &str), LayoutJob>
for Highlighter
{
impl egui::cache::ComputerMut<(&egui::FontId, &CodeTheme, &str, &str), LayoutJob> for Highlighter {
fn compute(
&mut self,
(font_id, theme, code, lang): (&egui::FontId, &CodeTheme, &str, &str),
Expand All @@ -44,7 +42,7 @@ pub fn highlight(
}
}

type HighlightCache = egui::util::cache::FrameCache<LayoutJob, Highlighter>;
type HighlightCache = egui::cache::FrameCache<LayoutJob, Highlighter>;

let font_id = style
.override_font_id
Expand Down

0 comments on commit d97b225

Please sign in to comment.