Skip to content

Commit

Permalink
preview caches and ringsets
Browse files Browse the repository at this point in the history
  • Loading branch information
alexpasmantier committed Oct 7, 2024
1 parent 941ed46 commit f2351bf
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 28 deletions.
1 change: 1 addition & 0 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
68 changes: 40 additions & 28 deletions src/components/previewers/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,85 +8,97 @@ 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<T> {
///
/// 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<T> {
ring_buffer: VecDeque<T>,
known_keys: HashSet<T>,
capacity: usize,
}

impl<T> SetRingBuffer<T>
impl<T> RingSet<T>
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<T> {
/// 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<T> {
// 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<T> {
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<T> {
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<String, Arc<Preview>>,
set_ring_buffer: SetRingBuffer<String>,
ring_set: RingSet<String>,
}

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),
}
}

pub fn get(&self, key: &str) -> Option<Arc<Preview>> {
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<Preview>) {
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);
}
}
}
Expand Down

0 comments on commit f2351bf

Please sign in to comment.