Skip to main content

oxilean_parse/expr_cache/
functions.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use super::types::CacheTier;
6
7#[cfg(test)]
8mod tests {
9    use super::*;
10    use crate::expr_cache::*;
11    #[test]
12    fn test_interner_new() {
13        let interner = StringInterner::new();
14        assert!(interner.is_empty());
15        assert_eq!(interner.len(), 0);
16    }
17    #[test]
18    fn test_intern_dedup() {
19        let mut interner = StringInterner::new();
20        let id1 = interner.intern("Nat");
21        let id2 = interner.intern("Nat");
22        let id3 = interner.intern("Type");
23        assert_eq!(id1, id2);
24        assert_ne!(id1, id3);
25        assert_eq!(interner.len(), 2);
26    }
27    #[test]
28    fn test_intern_lookup() {
29        let mut interner = StringInterner::new();
30        let id = interner.intern("Prop");
31        assert_eq!(interner.get(id), Some("Prop"));
32        assert!(interner.contains("Prop"));
33        assert!(!interner.contains("Bool"));
34    }
35    #[test]
36    fn test_decl_hash_compute() {
37        let h = DeclHash::compute("def foo : Nat := 0");
38        assert_ne!(h.value(), 0);
39    }
40    #[test]
41    fn test_decl_hash_same() {
42        let h1 = DeclHash::compute("theorem bar : True := trivial");
43        let h2 = DeclHash::compute("theorem bar : True := trivial");
44        let h3 = DeclHash::compute("theorem baz : True := trivial");
45        assert_eq!(h1, h2);
46        assert_ne!(h1, h3);
47    }
48    #[test]
49    fn test_parse_cache_lookup() {
50        let mut cache = ParseCache::new(10);
51        cache.insert("def foo : Nat := 0", Some("foo".to_string()));
52        assert!(cache.lookup("def foo : Nat := 0").is_some());
53        assert!(cache.lookup("def bar : Nat := 1").is_none());
54        assert!((cache.hit_rate() - 0.5).abs() < 1e-9);
55    }
56    #[test]
57    fn test_parse_cache_insert_evict() {
58        let mut cache = ParseCache::new(2);
59        cache.insert("def a := 1", Some("a".to_string()));
60        cache.insert("def b := 2", Some("b".to_string()));
61        assert_eq!(cache.len(), 2);
62        cache.insert("def c := 3", Some("c".to_string()));
63        assert_eq!(cache.len(), 2);
64    }
65    #[test]
66    fn test_hit_rate() {
67        let mut cache = ParseCache::new(10);
68        cache.insert("def x := 0", None);
69        cache.lookup("def x := 0");
70        cache.lookup("def x := 0");
71        cache.lookup("def y := 1");
72        let rate = cache.hit_rate();
73        assert!((rate - 2.0 / 3.0).abs() < 1e-9);
74    }
75}
76/// Deterministic FNV-1a hash.
77#[allow(dead_code)]
78pub fn fnv1a_hash(data: &[u8]) -> u64 {
79    let mut h: u64 = 14695981039346656037;
80    for &b in data {
81        h = h.wrapping_mul(1099511628211) ^ b as u64;
82    }
83    h
84}
85/// Mix two hashes.
86#[allow(dead_code)]
87pub fn mix_hashes(a: u64, b: u64) -> u64 {
88    let mut x = a ^ b.rotate_left(17);
89    x = x.wrapping_add(b);
90    x ^= x >> 31;
91    x = x.wrapping_mul(0x9e3779b97f4a7c15);
92    x ^= x >> 27;
93    x
94}
95/// Compute checksum.
96#[allow(dead_code)]
97pub fn compute_checksum(data: &str) -> u32 {
98    let mut sum: u32 = 0;
99    for (i, b) in data.bytes().enumerate() {
100        sum = sum.wrapping_add((b as u32).wrapping_mul(i as u32 + 1));
101    }
102    sum
103}
104/// Validate cache integrity.
105#[allow(dead_code)]
106pub fn validate_cache_integrity(data: &str, stored: u32) -> bool {
107    compute_checksum(data) == stored
108}
109/// Classify a cache entry into a tier based on access frequency.
110#[allow(dead_code)]
111pub fn classify_cache_entry(access_count: u64, age_ticks: u64) -> CacheTier {
112    let score = if age_ticks == 0 {
113        access_count as f64
114    } else {
115        access_count as f64 / age_ticks as f64
116    };
117    if score >= 1.0 {
118        CacheTier::Hot
119    } else if score >= 0.1 {
120        CacheTier::Warm
121    } else if score >= 0.01 {
122        CacheTier::Cold
123    } else {
124        CacheTier::Dead
125    }
126}
127#[cfg(test)]
128mod extended_expr_cache_tests {
129    use super::*;
130    use crate::expr_cache::*;
131    #[test]
132    fn test_fnv1a_hash_stable() {
133        let h1 = fnv1a_hash(b"hello");
134        let h2 = fnv1a_hash(b"hello");
135        assert_eq!(h1, h2);
136        assert_ne!(fnv1a_hash(b"hello"), fnv1a_hash(b"world"));
137    }
138    #[test]
139    fn test_mix_hashes() {
140        let a = fnv1a_hash(b"alpha");
141        let b = fnv1a_hash(b"beta");
142        let m = mix_hashes(a, b);
143        assert_ne!(m, a);
144        assert_ne!(m, b);
145    }
146    #[test]
147    fn test_parse_result_cache() {
148        let mut cache = ParseResultCache::new(10);
149        cache.store("x + y", "App".to_string(), 42);
150        assert!(cache.lookup("x + y").is_some());
151        assert!(cache.lookup("unknown").is_none());
152        assert_eq!(cache.stats().0, 1);
153    }
154    #[test]
155    fn test_segment_table() {
156        let src = "fun x -> x";
157        let mut table = SegmentTable::new();
158        let seg = ExprSegment::from_slice(src, 0, 5, SegmentKind::Lambda);
159        table.add(seg);
160        assert_eq!(table.count(), 1);
161        table.invalidate_range(0, 5);
162        assert_eq!(table.count(), 0);
163    }
164    #[test]
165    fn test_subexpr_frequency_map() {
166        let mut map = SubexprFrequencyMap::new();
167        map.record(42);
168        map.record(42);
169        map.record(7);
170        assert_eq!(map.frequency(42), 2);
171        assert_eq!(map.total_unique(), 2);
172    }
173    #[test]
174    fn test_alpha_eq_cache() {
175        let mut c = AlphaEqCache::new();
176        c.mark_equal(1, 2);
177        assert_eq!(c.query(2, 1), Some(true));
178        c.mark_inequal(3, 4);
179        assert_eq!(c.query(3, 4), Some(false));
180    }
181    #[test]
182    fn test_cache_pressure_monitor() {
183        let mut m = CachePressureMonitor::new();
184        m.record_insert(10);
185        m.record_lookup(true);
186        m.record_lookup(false);
187        m.record_eviction();
188        assert!((m.hit_rate() - 0.5).abs() < 1e-9);
189    }
190    #[test]
191    fn test_string_pool() {
192        let mut p = StringPool::new();
193        p.intern("hello");
194        p.intern("hello");
195        p.intern("world");
196        assert_eq!(p.count(), 2);
197        assert_eq!(p.saved_bytes(), 5);
198    }
199    #[test]
200    fn test_window_cache() {
201        let mut c: WindowCache<i32, &str> = WindowCache::new(2);
202        c.insert(1, "a");
203        c.insert(2, "b");
204        c.insert(3, "c");
205        assert_eq!(c.get(&1), None);
206        assert_eq!(c.get(&3), Some(&"c"));
207    }
208    #[test]
209    fn test_cache_integrity() {
210        let d = "theorem foo";
211        let cs = compute_checksum(d);
212        assert!(validate_cache_integrity(d, cs));
213        assert!(!validate_cache_integrity(d, cs.wrapping_add(1)));
214    }
215    #[test]
216    fn test_classify_entry() {
217        assert_eq!(classify_cache_entry(10, 1), CacheTier::Hot);
218        assert_eq!(classify_cache_entry(0, 1000), CacheTier::Dead);
219    }
220    #[test]
221    fn test_versioned_cache() {
222        let mut c: VersionedCache<&str, i32> = VersionedCache::new();
223        c.insert("x", 10);
224        assert_eq!(c.get(&"x"), Some(&10));
225        c.bump_version();
226        assert_eq!(c.get(&"x"), None);
227    }
228    #[test]
229    fn test_bloom_filter() {
230        let mut bf = BloomFilter::new(1024, 3);
231        bf.insert(42);
232        assert!(bf.may_contain(42));
233        bf.clear();
234    }
235    #[test]
236    fn test_nesting_depth() {
237        let mut t = NestingDepthTracker::new(3);
238        assert!(t.enter().is_ok());
239        assert!(t.enter().is_ok());
240        assert!(t.enter().is_ok());
241        assert!(t.enter().is_err());
242        t.exit();
243        assert!(t.enter().is_ok());
244    }
245    #[test]
246    fn test_rolling_hash() {
247        let mut rh = RollingHash::new(3);
248        rh.push(b'a');
249        rh.push(b'b');
250        rh.push(b'c');
251        assert!(rh.window_full());
252        let h1 = rh.current_hash();
253        rh.push(b'd');
254        assert_ne!(rh.current_hash(), h1);
255    }
256    #[test]
257    fn test_windowed_metrics() {
258        let mut m = WindowedCacheMetrics::new(100);
259        m.record_hit();
260        m.record_miss();
261        assert!((m.hit_rate() - 0.5).abs() < 1e-9);
262        m.reset();
263        assert_eq!(m.window_hits, 0);
264    }
265    #[test]
266    fn test_cache_health_report() {
267        let r = CacheHealthReport {
268            total_entries: 100,
269            hot_entries: 60,
270            warm_entries: 20,
271            cold_entries: 10,
272            dead_entries: 10,
273            estimated_waste_pct: 10.0,
274        };
275        assert!(r.is_healthy());
276        assert!(r.summary().contains("total=100"));
277    }
278}
279#[cfg(test)]
280mod extended_expr_cache_tests_2 {
281    use super::*;
282    use crate::expr_cache::*;
283    #[test]
284    fn test_expr_location_index() {
285        let mut idx = ExprLocationIndex::new();
286        idx.record(42, 10, 20);
287        idx.record(42, 30, 40);
288        assert_eq!(idx.count_occurrences(42), 2);
289        assert_eq!(idx.total_tracked(), 2);
290    }
291    #[test]
292    fn test_cache_coverage_report() {
293        let mut r = CacheCoverageReport::new();
294        r.record_cached(1000);
295        r.record_uncached(500);
296        assert!((r.coverage_pct() - 66.666).abs() < 0.01);
297    }
298    #[test]
299    fn test_namespaced_cache() {
300        let mut c: NamespacedCache<&str, i32> = NamespacedCache::new();
301        c.insert("math", "pi", 314);
302        assert_eq!(c.get("math", &"pi"), Some(&314));
303        c.invalidate_namespace("math");
304        assert_eq!(c.get("math", &"pi"), None);
305    }
306    #[test]
307    fn test_type_check_cache() {
308        let mut tc = TypeCheckCache::new(5);
309        let r = TypeCheckResult {
310            expr_hash: 99,
311            inferred_type: "Nat".into(),
312            is_valid: true,
313            check_time_us: 10,
314        };
315        tc.store(r);
316        assert!(tc.lookup(99).is_some());
317        tc.invalidate(99);
318        assert!(tc.lookup(99).is_none());
319    }
320    #[test]
321    fn test_cache_prewarmer() {
322        let sources = vec!["x".into(), "y".into()];
323        let mut w = CachePrewarmer::new(sources);
324        let mut c = ParseResultCache::new(100);
325        let n = w.prewarm_all(&mut c);
326        assert_eq!(n, 2);
327        let n2 = w.prewarm_all(&mut c);
328        assert_eq!(n2, 0);
329    }
330    #[test]
331    fn test_hash_set_64() {
332        let mut hs = HashSet64::new();
333        assert!(hs.insert(42));
334        assert!(!hs.insert(42));
335        assert!(hs.contains(42));
336        hs.clear();
337        assert!(hs.is_empty());
338    }
339    #[test]
340    fn test_two_queue_cache() {
341        let mut c: TwoQueueCache<String, i32> = TwoQueueCache::new(4);
342        c.insert("a".into(), 1);
343        c.insert("b".into(), 2);
344        assert_eq!(c.get(&"a".into()), Some(&1));
345        assert_eq!(c.get(&"z".into()), None);
346    }
347}
348#[cfg(test)]
349mod extended_expr_cache_tests_3 {
350    use super::*;
351    use crate::expr_cache::*;
352    #[test]
353    fn test_lfu_eviction() {
354        let p = LfuEviction::new(1, 0.0);
355        assert!(!p.should_evict(2, 0, 100));
356        assert!(p.should_evict(0, 0, 100));
357        assert_eq!(p.policy_name(), "LFU-Age");
358    }
359    #[test]
360    fn test_ttl_eviction() {
361        let p = TtlEviction::new(5);
362        assert!(!p.should_evict(0, 10, 14));
363        assert!(p.should_evict(0, 10, 16));
364        assert_eq!(p.policy_name(), "TTL");
365    }
366    #[test]
367    fn test_macro_expansion_cache() {
368        let mut c = MacroExpansionCache::new(10);
369        c.store(MacroExpansionEntry {
370            macro_hash: 1,
371            arg_hash: 2,
372            expansion: "exp".into(),
373            expansion_depth: 1,
374            use_count: 0,
375        });
376        assert!(c.lookup(1, 2).is_some());
377        assert_eq!(c.total_stored(), 1);
378    }
379    #[test]
380    fn test_lru_cache() {
381        let mut c: LruCache<&str> = LruCache::new(3);
382        c.insert(1, "a");
383        c.insert(2, "b");
384        c.insert(3, "c");
385        c.insert(4, "d");
386        assert!(!c.contains(1));
387        assert_eq!(c.get(4), Some(&"d"));
388    }
389    #[test]
390    fn test_expr_pool() {
391        let mut p = ExprPool::new();
392        let h = p.intern("Nat".to_string());
393        let h2 = p.intern("Nat".to_string());
394        assert_eq!(h, h2);
395        assert_eq!(p.total_refs(), 2);
396        p.release(h);
397        assert_eq!(p.total_refs(), 1);
398        p.release(h);
399        assert_eq!(p.total_exprs(), 0);
400    }
401    #[test]
402    fn test_memo_table() {
403        let mut t = MemoTable::new();
404        t.store(
405            0,
406            "expr",
407            MemoEntry {
408                end_pos: 5,
409                result: "x".into(),
410                success: true,
411            },
412        );
413        let found = t.lookup(0, "expr");
414        assert!(found.is_some());
415        assert_eq!(found.expect("test operation should succeed").end_pos, 5);
416    }
417    #[test]
418    fn test_global_expr_table() {
419        let mut t = GlobalExprTable::new();
420        let id1 = t.intern("Nat");
421        let id2 = t.intern("Nat");
422        assert_eq!(id1, id2);
423        let id3 = t.intern("Bool");
424        assert_ne!(id1, id3);
425        assert_eq!(t.lookup_repr(id1), Some("Nat"));
426        assert_eq!(t.table_size(), 2);
427    }
428    #[test]
429    fn test_symbol_interner() {
430        let mut si = SymbolInterner::new();
431        let id1 = si.intern("foo");
432        let id2 = si.intern("foo");
433        assert_eq!(id1, id2);
434        let id3 = si.intern("bar");
435        assert_ne!(id1, id3);
436        assert_eq!(si.lookup(id1), Some("foo"));
437        assert_eq!(si.size(), 2);
438        assert!(si.contains("foo"));
439        assert!(!si.contains("baz"));
440    }
441}
442/// DJB2 hash for expressions.
443#[allow(dead_code)]
444pub fn djb2_hash(s: &str) -> u64 {
445    let mut hash: u64 = 5381;
446    for b in s.bytes() {
447        hash = hash.wrapping_mul(33).wrapping_add(b as u64);
448    }
449    hash
450}
451/// Combined hash: mixes FNV-1a and DJB2.
452#[allow(dead_code)]
453pub fn combined_hash(s: &str) -> u64 {
454    let fnv = fnv1a_hash(s.as_bytes());
455    let djb = djb2_hash(s);
456    mix_hashes(fnv, djb)
457}
458/// Checks if two expression strings are alpha-equivalent by their hashes.
459#[allow(dead_code)]
460pub fn hash_alpha_equiv(a: &str, b: &str) -> bool {
461    combined_hash(a) == combined_hash(b)
462}
463/// Estimate memory usage of a cached string in bytes.
464#[allow(dead_code)]
465pub fn estimate_string_memory(s: &str) -> usize {
466    s.len() + std::mem::size_of::<String>() + 8
467}
468/// Build a simple cache key from multiple components.
469#[allow(dead_code)]
470pub fn build_cache_key(parts: &[&str]) -> u64 {
471    let mut h: u64 = 0;
472    for part in parts {
473        h = mix_hashes(h, fnv1a_hash(part.as_bytes()));
474    }
475    h
476}
477#[cfg(test)]
478mod extended_expr_cache_tests_4 {
479    use super::*;
480    use crate::expr_cache::*;
481    #[test]
482    fn test_bump_allocator() {
483        let mut alloc = BumpAllocator::new(100);
484        let pos = alloc
485            .alloc_str("hello")
486            .expect("test operation should succeed");
487        assert_eq!(alloc.get_str(pos, 5), Some("hello"));
488        assert_eq!(alloc.used(), 5);
489        alloc.reset();
490        assert_eq!(alloc.used(), 0);
491    }
492    #[test]
493    fn test_token_frequency_table() {
494        let mut t = TokenFrequencyTable::new();
495        t.record("def");
496        t.record("def");
497        t.record("fun");
498        assert_eq!(t.count("def"), 2);
499        assert_eq!(t.unique_tokens(), 2);
500        assert_eq!(t.total_tokens(), 3);
501        let top = t.top_n(1);
502        assert_eq!(top[0].0, "def");
503    }
504    #[test]
505    fn test_cache_warmup() {
506        let w = CacheWarmup::new(vec!["x".into(), "y".into()]).with_priority(CachePriority::High);
507        assert_eq!(w.source_count(), 2);
508        assert_eq!(w.priority, CachePriority::High);
509    }
510    #[test]
511    fn test_cache_report() {
512        let r = CacheReport::new(100, 80, 20, 5, 1024);
513        assert!((r.hit_rate() - 0.8).abs() < 1e-9);
514        let s = r.summary();
515        assert!(s.contains("hit_rate=80.0%"));
516    }
517    #[test]
518    fn test_token_window() {
519        let mut w = TokenWindow::new(3);
520        w.push("a");
521        w.push("b");
522        w.push("c");
523        assert!(w.is_full());
524        w.push("d");
525        assert!(!w.contains("a"));
526        assert!(w.contains("d"));
527    }
528    #[test]
529    fn test_djb2_hash() {
530        let h1 = djb2_hash("hello");
531        let h2 = djb2_hash("hello");
532        assert_eq!(h1, h2);
533        assert_ne!(djb2_hash("hello"), djb2_hash("world"));
534    }
535    #[test]
536    fn test_combined_hash() {
537        let h = combined_hash("theorem foo : Nat");
538        assert!(h > 0);
539        assert_eq!(combined_hash("x"), combined_hash("x"));
540        assert_ne!(combined_hash("x"), combined_hash("y"));
541    }
542    #[test]
543    fn test_build_cache_key() {
544        let k1 = build_cache_key(&["rule1", "pos:5"]);
545        let k2 = build_cache_key(&["rule1", "pos:5"]);
546        assert_eq!(k1, k2);
547        assert_ne!(build_cache_key(&["a"]), build_cache_key(&["b"]));
548    }
549    #[test]
550    fn test_estimate_string_memory() {
551        let m = estimate_string_memory("hello");
552        assert!(m >= 5);
553    }
554    #[test]
555    fn test_interning_stats() {
556        let mut stats = InterningStats::new();
557        stats.record_new();
558        stats.record_new();
559        stats.record_hit(10);
560        assert_eq!(stats.unique_strings, 2);
561        assert_eq!(stats.bytes_saved, 10);
562        assert!((stats.dedup_ratio() - 1.5).abs() < 1e-9);
563    }
564    #[test]
565    fn test_hash_alpha_equiv() {
566        assert!(hash_alpha_equiv("hello", "hello"));
567        assert!(!hash_alpha_equiv("foo", "bar"));
568    }
569}
570#[cfg(test)]
571mod extended_expr_cache_tests_5 {
572    use super::*;
573    use crate::expr_cache::*;
574    #[test]
575    fn test_cache_key_builder() {
576        let k1 = CacheKeyBuilder::new()
577            .with_str("expr")
578            .with_usize(5)
579            .build();
580        let k2 = CacheKeyBuilder::new()
581            .with_str("expr")
582            .with_usize(5)
583            .build();
584        assert_eq!(k1, k2);
585        let k3 = CacheKeyBuilder::new().with_str("ty").with_usize(5).build();
586        assert_ne!(k1, k3);
587    }
588    #[test]
589    fn test_adaptive_lru_cache() {
590        let mut c: AdaptiveLruCache<i32> = AdaptiveLruCache::new(10, 5, 100);
591        c.insert(1, 42);
592        assert_eq!(c.get(1), Some(&42));
593        assert_eq!(c.get(99), None);
594        assert_eq!(c.hit_rate(), 0.5);
595    }
596    #[test]
597    fn test_expr_diff_cache() {
598        let mut c = ExprDiffCache::new(10);
599        c.store(1, 2, "diff text");
600        assert_eq!(c.lookup(1, 2), Some("diff text"));
601        assert_eq!(c.lookup(2, 1), Some("diff text"));
602        assert_eq!(c.size(), 1);
603    }
604    #[test]
605    fn test_multi_level_cache() {
606        let mut c: MultiLevelCache<String> = MultiLevelCache::new(2, 10);
607        c.insert(1, "a".to_string());
608        c.insert(2, "b".to_string());
609        assert_eq!(c.get(&1), Some("a".to_string()));
610        assert_eq!(c.get(&99), None);
611    }
612    #[test]
613    fn test_persistent_cache() {
614        let mut c = PersistentCache::new();
615        c.insert(42, "hello");
616        c.insert(99, "world");
617        let s = c.serialize();
618        let c2 = PersistentCache::deserialize(&s);
619        assert_eq!(c2.lookup(42), Some("hello"));
620        assert_eq!(c2.lookup(99), Some("world"));
621        assert_eq!(c2.entry_count(), 2);
622    }
623}