From f2351bfcf2abf2a2097730cb53f31299774866f9 Mon Sep 17 00:00:00 2001 From: alexpasmantier Date: Mon, 7 Oct 2024 18:53:20 +0200 Subject: [PATCH] preview caches and ringsets --- TODO.md | 1 + src/components/previewers/cache.rs | 68 ++++++++++++++++++------------ 2 files changed, 41 insertions(+), 28 deletions(-) diff --git a/TODO.md b/TODO.md index fc8df69..a95ac67 100644 --- a/TODO.md +++ b/TODO.md @@ -13,6 +13,7 @@ - [x] async finder search - [x] use nucleo for env - [ ] better keymaps +- [ ] mutualize placeholder previews in cache (really not a priority) ## feature ideas - [ ] some sort of iterative fuzzy file explorer (preview contents of folders on the right, enter to go in etc.) maybe diff --git a/src/components/previewers/cache.rs b/src/components/previewers/cache.rs index 22a15fc..11ce937 100644 --- a/src/components/previewers/cache.rs +++ b/src/components/previewers/cache.rs @@ -8,69 +8,81 @@ use tracing::debug; use crate::components::previewers::Preview; /// A ring buffer that also keeps track of the keys it contains to avoid duplicates. -struct SetRingBuffer { +/// +/// I'm planning on using this as a backend LRU-cache for the preview cache. +/// Basic idea: +/// - When a new key is pushed, if it's already in the buffer, do nothing. +/// - If the buffer is full, remove the oldest key and push the new key. +struct RingSet { ring_buffer: VecDeque, known_keys: HashSet, capacity: usize, } -impl SetRingBuffer +impl RingSet where T: Eq + std::hash::Hash + Clone + std::fmt::Debug, { pub fn with_capacity(capacity: usize) -> Self { - SetRingBuffer { + RingSet { ring_buffer: VecDeque::with_capacity(capacity), known_keys: HashSet::with_capacity(capacity), capacity, } } - // TODO: finish this - pub fn push(&mut self, key: T) -> Option { + /// Push a new item to the back of the buffer, removing the oldest item if the buffer is full. + /// Returns the item that was removed, if any. + /// If the item is already in the buffer, do nothing and return None. + pub fn push(&mut self, item: T) -> Option { // If the key is already in the buffer, do nothing - if self.contains(&key) { - debug!("Key already in ring buffer: {:?}", key); + if self.contains(&item) { + debug!("Key already in ring buffer: {:?}", item); return None; } - // If the buffer is full, remove the oldest key + let mut popped_key = None; + // If the buffer is full, remove the oldest key (e.g. pop from the front of the buffer) if self.ring_buffer.len() >= self.capacity { - self.pop(); + popped_key = self.pop(); } - // finally, push the new key - self.ring_buffer.push_back(key.clone()); - self.known_keys.insert(key); - None + // finally, push the new key to the back of the buffer + self.ring_buffer.push_back(item.clone()); + self.known_keys.insert(item); + popped_key } - pub fn pop(&mut self) -> Option { - if let Some(key) = self.ring_buffer.pop_front() { - debug!("Removing key from ring buffer: {:?}", key); - self.known_keys.remove(&key); - Some(key) + fn pop(&mut self) -> Option { + if let Some(item) = self.ring_buffer.pop_front() { + debug!("Removing key from ring buffer: {:?}", item); + self.known_keys.remove(&item); + Some(item) } else { None } } - pub fn contains(&self, key: &T) -> bool { + fn contains(&self, key: &T) -> bool { self.known_keys.contains(key) } } +/// Default size of the preview cache. +/// This does seem kind of arbitrary for now, will need to play around with it. const DEFAULT_PREVIEW_CACHE_SIZE: usize = 100; /// A cache for previews. +/// The cache is implemented as a LRU cache with a fixed size. pub struct PreviewCache { entries: HashMap>, - set_ring_buffer: SetRingBuffer, + ring_set: RingSet, } impl PreviewCache { - pub fn new(max_size: usize) -> Self { + /// Create a new preview cache with the given capacity. + pub fn new(capacity: usize) -> Self { PreviewCache { entries: HashMap::new(), - set_ring_buffer: SetRingBuffer::with_capacity(max_size), + ring_set: RingSet::with_capacity(capacity), } } @@ -78,15 +90,15 @@ impl PreviewCache { self.entries.get(key).cloned() } + /// Insert a new preview into the cache. + /// If the cache is full, the oldest entry will be removed. + /// If the key is already in the cache, the preview will be updated. pub fn insert(&mut self, key: String, preview: Arc) { debug!("Inserting preview into cache: {}", key); self.entries.insert(key.clone(), preview.clone()); - self.set_ring_buffer.push(key); - if self.entry_buffer.len() >= self.max_size { - if let Some(oldest_key) = self.entry_buffer.pop_front() { - debug!("Cache full, removing oldest entry: {}", oldest_key); - self.entries.remove(&oldest_key); - } + if let Some(oldest_key) = self.ring_set.push(key) { + debug!("Cache full, removing oldest entry: {}", oldest_key); + self.entries.remove(&oldest_key); } } }