eryon_nrt/transform/
cache.rs

1/*
2    Appellation: cache <module>
3    Contrib: @FL03
4*/
5use super::Path;
6use std::collections::HashMap;
7
8// Add to Transformer
9#[derive(Clone, Debug, PartialEq)]
10pub struct PathCache {
11    /// Cache of computed paths from one pitch set to another
12    paths: HashMap<([usize; 3], usize), Vec<Path>>,
13    /// Maximum number of entries to store
14    capacity: usize,
15    /// Usage counts to implement LRU eviction
16    usage: HashMap<([usize; 3], usize), usize>,
17}
18
19impl PathCache {
20    pub fn new(capacity: usize) -> Self {
21        PathCache {
22            paths: HashMap::new(),
23            capacity,
24            usage: HashMap::new(),
25        }
26    }
27
28    pub fn get(&mut self, from_triad: &[usize; 3], to_pitch: usize) -> Option<&Vec<Path>> {
29        let key = (*from_triad, to_pitch);
30
31        // Update usage count
32        if let Some(count) = self.usage.get_mut(&key) {
33            *count += 1;
34        }
35
36        self.paths.get(&key)
37    }
38
39    pub fn insert(&mut self, from_triad: [usize; 3], to_pitch: usize, paths: Vec<Path>) {
40        let key = (from_triad, to_pitch);
41
42        // If we're at capacity, evict the least used entry
43        if self.paths.len() >= self.capacity && !self.paths.contains_key(&key) {
44            if let Some((lru_key, _)) = self.usage.iter().min_by_key(|(_, count)| **count) {
45                let lru_key = *lru_key;
46                self.paths.remove(&lru_key);
47                self.usage.remove(&lru_key);
48            }
49        }
50
51        self.paths.insert(key, paths);
52        self.usage.insert(key, 1);
53    }
54}