Skip to main content

forge_lint/sol/analysis/
helper_cache.rs

1use std::{
2    collections::{HashMap, HashSet, VecDeque},
3    hash::Hash,
4};
5
6pub const DEFAULT_HELPER_ANALYSIS_CACHE_LIMIT: usize = 65_536;
7
8/// Bounded memo table for lint analyses that inline internal helper calls.
9#[derive(Debug)]
10pub struct HelperAnalysisCache<K, V> {
11    entries: HashMap<K, V>,
12    in_progress: HashSet<K>,
13    order: VecDeque<K>,
14    max_entries: usize,
15}
16
17impl<K, V> HelperAnalysisCache<K, V>
18where
19    K: Clone + Eq + Hash,
20{
21    pub fn new(max_entries: usize) -> Self {
22        Self {
23            entries: HashMap::new(),
24            in_progress: HashSet::new(),
25            order: VecDeque::new(),
26            max_entries,
27        }
28    }
29
30    pub fn is_in_progress(&self, key: &K) -> bool {
31        self.in_progress.contains(key)
32    }
33
34    pub fn get(&self, key: &K) -> Option<&V> {
35        self.entries.get(key)
36    }
37
38    pub fn start(&mut self, key: K) {
39        self.in_progress.insert(key);
40    }
41
42    pub fn finish(&mut self, key: K, value: V) {
43        self.in_progress.remove(&key);
44        if self.max_entries == 0 {
45            return;
46        }
47
48        if !self.entries.contains_key(&key) {
49            self.order.push_back(key.clone());
50        }
51        self.entries.insert(key, value);
52
53        while self.entries.len() > self.max_entries {
54            if let Some(oldest) = self.order.pop_front() {
55                self.entries.remove(&oldest);
56                self.in_progress.remove(&oldest);
57            } else {
58                break;
59            }
60        }
61    }
62}