1use crate::term::{Term, TermId, TermKind};
7use std::collections::HashMap;
8
9pub struct Arena {
11 terms: Vec<Term>,
13
14 cache: HashMap<u64, Vec<TermId>>,
16
17 stats: ArenaStats,
19}
20
21#[derive(Debug, Default, Clone)]
23pub struct ArenaStats {
24 pub allocated: usize,
26
27 pub cache_hits: usize,
29
30 pub cache_misses: usize,
32}
33
34impl Arena {
35 pub fn new() -> Self {
37 Self {
38 terms: Vec::new(),
39 cache: HashMap::new(),
40 stats: ArenaStats::default(),
41 }
42 }
43
44 pub fn intern(&mut self, kind: TermKind) -> TermId {
46 let term = Term::new(kind);
47 let hash = term.hash();
48
49 if let Some(candidates) = self.cache.get(&hash) {
51 for &id in candidates {
52 if let Some(existing) = self.terms.get(id.raw() as usize) {
53 if existing.kind == term.kind {
54 self.stats.cache_hits += 1;
55 return id;
56 }
57 }
58 }
59 }
60
61 self.stats.cache_misses += 1;
63 self.stats.allocated += 1;
64
65 let id = TermId::new(self.terms.len() as u32);
66 self.terms.push(term);
67
68 self.cache.entry(hash).or_insert_with(Vec::new).push(id);
70
71 id
72 }
73
74 pub fn get(&self, id: TermId) -> Option<&Term> {
76 self.terms.get(id.raw() as usize)
77 }
78
79 pub fn get_term(&self, id: TermId) -> Option<&Term> {
81 self.get(id)
82 }
83
84 pub fn kind(&self, id: TermId) -> Option<&TermKind> {
86 self.get(id).map(|t| &t.kind)
87 }
88
89 pub fn terms(&self) -> usize {
91 self.terms.len()
92 }
93
94 pub fn stats(&self) -> &ArenaStats {
96 &self.stats
97 }
98
99 pub fn cache_hit_rate(&self) -> f64 {
101 if self.stats.cache_hits + self.stats.cache_misses == 0 {
102 return 0.0;
103 }
104 self.stats.cache_hits as f64
105 / (self.stats.cache_hits + self.stats.cache_misses) as f64
106 }
107
108 pub fn clear_stats(&mut self) {
110 self.stats = ArenaStats::default();
111 }
112
113 pub fn mk_sort(&mut self, level: crate::level::LevelId) -> TermId {
117 self.intern(TermKind::Sort(level))
118 }
119
120 pub fn mk_const(
122 &mut self,
123 name: crate::symbol::SymbolId,
124 levels: Vec<crate::level::LevelId>,
125 ) -> TermId {
126 self.intern(TermKind::Const(name, levels))
127 }
128
129 pub fn mk_var(&mut self, index: u32) -> TermId {
131 self.intern(TermKind::Var(index))
132 }
133
134 pub fn mk_app(&mut self, func: TermId, arg: TermId) -> TermId {
136 self.intern(TermKind::App(func, arg))
137 }
138
139 pub fn mk_lam(&mut self, binder: crate::term::Binder, body: TermId) -> TermId {
141 self.intern(TermKind::Lam(binder, body))
142 }
143
144 pub fn mk_pi(&mut self, binder: crate::term::Binder, body: TermId) -> TermId {
146 self.intern(TermKind::Pi(binder, body))
147 }
148
149 pub fn mk_let(
151 &mut self,
152 binder: crate::term::Binder,
153 value: TermId,
154 body: TermId,
155 ) -> TermId {
156 self.intern(TermKind::Let(binder, value, body))
157 }
158
159 pub fn mk_mvar(&mut self, id: crate::term::MetaVarId) -> TermId {
161 self.intern(TermKind::MVar(id))
162 }
163
164 pub fn mk_nat(&mut self, n: u64) -> TermId {
166 self.intern(TermKind::Lit(crate::term::Literal::Nat(n)))
167 }
168
169 pub fn mk_app_spine(&mut self, func: TermId, args: &[TermId]) -> TermId {
171 args.iter().fold(func, |acc, &arg| self.mk_app(acc, arg))
172 }
173
174 pub fn mk_level_zero(&mut self) -> crate::level::LevelId {
176 crate::level::LevelId::new(0)
178 }
179}
180
181impl Default for Arena {
182 fn default() -> Self {
183 Self::new()
184 }
185}
186
187#[cfg(test)]
188mod tests {
189 use super::*;
190 use crate::level::LevelId;
191
192 #[test]
193 fn test_hash_consing() {
194 let mut arena = Arena::new();
195
196 let var0_1 = arena.mk_var(0);
197 let var0_2 = arena.mk_var(0);
198
199 assert_eq!(var0_1, var0_2);
201 assert_eq!(arena.terms(), 1);
202 assert!(arena.stats().cache_hits > 0);
203 }
204
205 #[test]
206 fn test_different_terms() {
207 let mut arena = Arena::new();
208
209 let var0 = arena.mk_var(0);
210 let var1 = arena.mk_var(1);
211
212 assert_ne!(var0, var1);
213 assert_eq!(arena.terms(), 2);
214 }
215
216 #[test]
217 fn test_app_spine() {
218 let mut arena = Arena::new();
219
220 let f = arena.mk_var(0);
221 let x = arena.mk_var(1);
222 let y = arena.mk_var(2);
223
224 let app = arena.mk_app_spine(f, &[x, y]);
225
226 if let Some(TermKind::App(left, _)) = arena.kind(app) {
228 if let Some(TermKind::App(_, _)) = arena.kind(*left) {
229 } else {
231 panic!("Expected nested application");
232 }
233 } else {
234 panic!("Expected application");
235 }
236 }
237
238 #[test]
239 fn test_cache_efficiency() {
240 let mut arena = Arena::new();
241
242 for _ in 0..100 {
244 arena.mk_var(0);
245 }
246
247 assert!(arena.cache_hit_rate() > 0.95);
249 assert_eq!(arena.terms(), 1);
250 }
251}