aether/
cache.rs

1// src/cache.rs
2//! AST缓存机制,减少重复解析
3
4use crate::ast::Program;
5use std::collections::HashMap;
6use std::collections::hash_map::DefaultHasher;
7use std::hash::{Hash, Hasher};
8
9/// AST缓存,用于存储已解析的程序
10#[derive(Debug)]
11pub struct ASTCache {
12    /// 缓存存储: hash -> 解析后的AST
13    cache: HashMap<u64, Program>,
14    /// 缓存大小限制
15    max_size: usize,
16    /// 缓存命中统计
17    hits: usize,
18    /// 缓存未命中统计
19    misses: usize,
20}
21
22impl ASTCache {
23    /// 创建新的AST缓存
24    pub fn new() -> Self {
25        Self::with_capacity(100)
26    }
27
28    /// 创建指定容量的AST缓存
29    pub fn with_capacity(max_size: usize) -> Self {
30        ASTCache {
31            cache: HashMap::with_capacity(max_size.min(100)),
32            max_size,
33            hits: 0,
34            misses: 0,
35        }
36    }
37
38    /// 计算代码的哈希值
39    fn hash_code(code: &str) -> u64 {
40        let mut hasher = DefaultHasher::new();
41        code.hash(&mut hasher);
42        hasher.finish()
43    }
44
45    /// 从缓存中获取AST
46    pub fn get(&mut self, code: &str) -> Option<Program> {
47        let hash = Self::hash_code(code);
48        if let Some(program) = self.cache.get(&hash) {
49            self.hits += 1;
50            Some(program.clone())
51        } else {
52            self.misses += 1;
53            None
54        }
55    }
56
57    /// 将AST存入缓存
58    pub fn insert(&mut self, code: &str, program: Program) {
59        let hash = Self::hash_code(code);
60
61        // 如果缓存已满,使用简单的FIFO策略清理
62        if self.cache.len() >= self.max_size {
63            // 清理最早的10%条目
64            let to_remove = (self.max_size / 10).max(1);
65            let keys_to_remove: Vec<u64> = self.cache.keys().take(to_remove).copied().collect();
66            for key in keys_to_remove {
67                self.cache.remove(&key);
68            }
69        }
70
71        self.cache.insert(hash, program);
72    }
73
74    /// 清空缓存
75    pub fn clear(&mut self) {
76        self.cache.clear();
77        self.hits = 0;
78        self.misses = 0;
79    }
80
81    /// 获取缓存统计信息
82    pub fn stats(&self) -> CacheStats {
83        CacheStats {
84            size: self.cache.len(),
85            max_size: self.max_size,
86            hits: self.hits,
87            misses: self.misses,
88            hit_rate: if self.hits + self.misses > 0 {
89                self.hits as f64 / (self.hits + self.misses) as f64
90            } else {
91                0.0
92            },
93        }
94    }
95}
96
97impl Default for ASTCache {
98    fn default() -> Self {
99        Self::new()
100    }
101}
102
103/// 缓存统计信息
104#[derive(Debug, Clone)]
105pub struct CacheStats {
106    /// 当前缓存大小
107    pub size: usize,
108    /// 最大缓存大小
109    pub max_size: usize,
110    /// 缓存命中次数
111    pub hits: usize,
112    /// 缓存未命中次数
113    pub misses: usize,
114    /// 缓存命中率
115    pub hit_rate: f64,
116}
117
118impl std::fmt::Display for CacheStats {
119    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
120        write!(
121            f,
122            "Cache Stats: size={}/{}, hits={}, misses={}, hit_rate={:.2}%",
123            self.size,
124            self.max_size,
125            self.hits,
126            self.misses,
127            self.hit_rate * 100.0
128        )
129    }
130}
131
132#[cfg(test)]
133mod tests {
134    use super::*;
135
136    #[test]
137    fn test_cache_basic() {
138        let mut cache = ASTCache::new();
139        let code = "Set X 10";
140
141        // 第一次获取应该失败
142        assert!(cache.get(code).is_none());
143        assert_eq!(cache.stats().misses, 1);
144
145        // 插入后应该能获取
146        let program: Program = vec![];
147        cache.insert(code, program.clone());
148        assert!(cache.get(code).is_some());
149        assert_eq!(cache.stats().hits, 1);
150    }
151
152    #[test]
153    fn test_cache_capacity() {
154        let mut cache = ASTCache::with_capacity(5);
155        let program: Program = vec![];
156
157        // 插入超过容量的条目
158        for i in 0..10 {
159            let code = format!("Set X {}", i);
160            cache.insert(&code, program.clone());
161        }
162
163        // 缓存大小应该被限制
164        assert!(cache.stats().size <= 5);
165    }
166}