1use super::functions::*;
6use crate::expr_util::lift_loose_bvars;
7use std::collections::HashMap;
8
9#[allow(dead_code)]
11pub struct PathBuf {
12 components: Vec<String>,
13}
14#[allow(dead_code)]
15impl PathBuf {
16 pub fn new() -> Self {
18 Self {
19 components: Vec::new(),
20 }
21 }
22 pub fn push(&mut self, comp: impl Into<String>) {
24 self.components.push(comp.into());
25 }
26 pub fn pop(&mut self) {
28 self.components.pop();
29 }
30 pub fn as_str(&self) -> String {
32 self.components.join("/")
33 }
34 pub fn depth(&self) -> usize {
36 self.components.len()
37 }
38 pub fn clear(&mut self) {
40 self.components.clear();
41 }
42}
43#[allow(dead_code)]
45pub struct RawFnPtr {
46 ptr: usize,
48 arity: usize,
49 name: String,
50}
51#[allow(dead_code)]
52impl RawFnPtr {
53 pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
55 Self {
56 ptr,
57 arity,
58 name: name.into(),
59 }
60 }
61 pub fn arity(&self) -> usize {
63 self.arity
64 }
65 pub fn name(&self) -> &str {
67 &self.name
68 }
69 pub fn raw(&self) -> usize {
71 self.ptr
72 }
73}
74#[allow(dead_code)]
76pub struct TransformStat {
77 before: StatSummary,
78 after: StatSummary,
79}
80#[allow(dead_code)]
81impl TransformStat {
82 pub fn new() -> Self {
84 Self {
85 before: StatSummary::new(),
86 after: StatSummary::new(),
87 }
88 }
89 pub fn record_before(&mut self, v: f64) {
91 self.before.record(v);
92 }
93 pub fn record_after(&mut self, v: f64) {
95 self.after.record(v);
96 }
97 pub fn mean_ratio(&self) -> Option<f64> {
99 let b = self.before.mean()?;
100 let a = self.after.mean()?;
101 if b.abs() < f64::EPSILON {
102 return None;
103 }
104 Some(a / b)
105 }
106}
107#[allow(dead_code)]
109pub struct TokenBucket {
110 capacity: u64,
111 tokens: u64,
112 refill_per_ms: u64,
113 last_refill: std::time::Instant,
114}
115#[allow(dead_code)]
116impl TokenBucket {
117 pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
119 Self {
120 capacity,
121 tokens: capacity,
122 refill_per_ms,
123 last_refill: std::time::Instant::now(),
124 }
125 }
126 pub fn try_consume(&mut self, n: u64) -> bool {
128 self.refill();
129 if self.tokens >= n {
130 self.tokens -= n;
131 true
132 } else {
133 false
134 }
135 }
136 fn refill(&mut self) {
137 let now = std::time::Instant::now();
138 let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
139 if elapsed_ms > 0 {
140 let new_tokens = elapsed_ms * self.refill_per_ms;
141 self.tokens = (self.tokens + new_tokens).min(self.capacity);
142 self.last_refill = now;
143 }
144 }
145 pub fn available(&self) -> u64 {
147 self.tokens
148 }
149 pub fn capacity(&self) -> u64 {
151 self.capacity
152 }
153}
154#[allow(dead_code)]
156pub struct SlidingSum {
157 window: Vec<f64>,
158 capacity: usize,
159 pos: usize,
160 sum: f64,
161 count: usize,
162}
163#[allow(dead_code)]
164impl SlidingSum {
165 pub fn new(capacity: usize) -> Self {
167 Self {
168 window: vec![0.0; capacity],
169 capacity,
170 pos: 0,
171 sum: 0.0,
172 count: 0,
173 }
174 }
175 pub fn push(&mut self, val: f64) {
177 let oldest = self.window[self.pos];
178 self.sum -= oldest;
179 self.sum += val;
180 self.window[self.pos] = val;
181 self.pos = (self.pos + 1) % self.capacity;
182 if self.count < self.capacity {
183 self.count += 1;
184 }
185 }
186 pub fn sum(&self) -> f64 {
188 self.sum
189 }
190 pub fn mean(&self) -> Option<f64> {
192 if self.count == 0 {
193 None
194 } else {
195 Some(self.sum / self.count as f64)
196 }
197 }
198 pub fn count(&self) -> usize {
200 self.count
201 }
202}
203#[allow(dead_code)]
205pub struct ConfigNode {
206 key: String,
207 value: Option<String>,
208 children: Vec<ConfigNode>,
209}
210#[allow(dead_code)]
211impl ConfigNode {
212 pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
214 Self {
215 key: key.into(),
216 value: Some(value.into()),
217 children: Vec::new(),
218 }
219 }
220 pub fn section(key: impl Into<String>) -> Self {
222 Self {
223 key: key.into(),
224 value: None,
225 children: Vec::new(),
226 }
227 }
228 pub fn add_child(&mut self, child: ConfigNode) {
230 self.children.push(child);
231 }
232 pub fn key(&self) -> &str {
234 &self.key
235 }
236 pub fn value(&self) -> Option<&str> {
238 self.value.as_deref()
239 }
240 pub fn num_children(&self) -> usize {
242 self.children.len()
243 }
244 pub fn lookup(&self, path: &str) -> Option<&str> {
246 let mut parts = path.splitn(2, '.');
247 let head = parts.next()?;
248 let tail = parts.next();
249 if head != self.key {
250 return None;
251 }
252 match tail {
253 None => self.value.as_deref(),
254 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
255 }
256 }
257 fn lookup_relative(&self, path: &str) -> Option<&str> {
258 let mut parts = path.splitn(2, '.');
259 let head = parts.next()?;
260 let tail = parts.next();
261 if head != self.key {
262 return None;
263 }
264 match tail {
265 None => self.value.as_deref(),
266 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
267 }
268 }
269}
270#[allow(dead_code)]
272pub struct SimpleDag {
273 edges: Vec<Vec<usize>>,
275}
276#[allow(dead_code)]
277impl SimpleDag {
278 pub fn new(n: usize) -> Self {
280 Self {
281 edges: vec![Vec::new(); n],
282 }
283 }
284 pub fn add_edge(&mut self, from: usize, to: usize) {
286 if from < self.edges.len() {
287 self.edges[from].push(to);
288 }
289 }
290 pub fn successors(&self, node: usize) -> &[usize] {
292 self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
293 }
294 pub fn can_reach(&self, from: usize, to: usize) -> bool {
296 let mut visited = vec![false; self.edges.len()];
297 self.dfs(from, to, &mut visited)
298 }
299 fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
300 if cur == target {
301 return true;
302 }
303 if cur >= visited.len() || visited[cur] {
304 return false;
305 }
306 visited[cur] = true;
307 for &next in self.successors(cur) {
308 if self.dfs(next, target, visited) {
309 return true;
310 }
311 }
312 false
313 }
314 pub fn topological_sort(&self) -> Option<Vec<usize>> {
316 let n = self.edges.len();
317 let mut in_degree = vec![0usize; n];
318 for succs in &self.edges {
319 for &s in succs {
320 if s < n {
321 in_degree[s] += 1;
322 }
323 }
324 }
325 let mut queue: std::collections::VecDeque<usize> =
326 (0..n).filter(|&i| in_degree[i] == 0).collect();
327 let mut order = Vec::new();
328 while let Some(node) = queue.pop_front() {
329 order.push(node);
330 for &s in self.successors(node) {
331 if s < n {
332 in_degree[s] -= 1;
333 if in_degree[s] == 0 {
334 queue.push_back(s);
335 }
336 }
337 }
338 }
339 if order.len() == n {
340 Some(order)
341 } else {
342 None
343 }
344 }
345 pub fn num_nodes(&self) -> usize {
347 self.edges.len()
348 }
349}
350#[allow(dead_code)]
352pub enum Either2<A, B> {
353 First(A),
355 Second(B),
357}
358#[allow(dead_code)]
359impl<A, B> Either2<A, B> {
360 pub fn is_first(&self) -> bool {
362 matches!(self, Either2::First(_))
363 }
364 pub fn is_second(&self) -> bool {
366 matches!(self, Either2::Second(_))
367 }
368 pub fn first(self) -> Option<A> {
370 match self {
371 Either2::First(a) => Some(a),
372 _ => None,
373 }
374 }
375 pub fn second(self) -> Option<B> {
377 match self {
378 Either2::Second(b) => Some(b),
379 _ => None,
380 }
381 }
382 pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
384 match self {
385 Either2::First(a) => Either2::First(f(a)),
386 Either2::Second(b) => Either2::Second(b),
387 }
388 }
389}
390#[allow(dead_code)]
392#[allow(missing_docs)]
393pub enum DecisionNode {
394 Leaf(String),
396 Branch {
398 key: String,
399 val: String,
400 yes_branch: Box<DecisionNode>,
401 no_branch: Box<DecisionNode>,
402 },
403}
404#[allow(dead_code)]
405impl DecisionNode {
406 pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
408 match self {
409 DecisionNode::Leaf(action) => action.as_str(),
410 DecisionNode::Branch {
411 key,
412 val,
413 yes_branch,
414 no_branch,
415 } => {
416 let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
417 if actual == val.as_str() {
418 yes_branch.evaluate(ctx)
419 } else {
420 no_branch.evaluate(ctx)
421 }
422 }
423 }
424 }
425 pub fn depth(&self) -> usize {
427 match self {
428 DecisionNode::Leaf(_) => 0,
429 DecisionNode::Branch {
430 yes_branch,
431 no_branch,
432 ..
433 } => 1 + yes_branch.depth().max(no_branch.depth()),
434 }
435 }
436}
437#[allow(dead_code)]
439pub struct StackCalc {
440 stack: Vec<i64>,
441}
442#[allow(dead_code)]
443impl StackCalc {
444 pub fn new() -> Self {
446 Self { stack: Vec::new() }
447 }
448 pub fn push(&mut self, n: i64) {
450 self.stack.push(n);
451 }
452 pub fn add(&mut self) {
454 let b = self
455 .stack
456 .pop()
457 .expect("stack must have at least two values for add");
458 let a = self
459 .stack
460 .pop()
461 .expect("stack must have at least two values for add");
462 self.stack.push(a + b);
463 }
464 pub fn sub(&mut self) {
466 let b = self
467 .stack
468 .pop()
469 .expect("stack must have at least two values for sub");
470 let a = self
471 .stack
472 .pop()
473 .expect("stack must have at least two values for sub");
474 self.stack.push(a - b);
475 }
476 pub fn mul(&mut self) {
478 let b = self
479 .stack
480 .pop()
481 .expect("stack must have at least two values for mul");
482 let a = self
483 .stack
484 .pop()
485 .expect("stack must have at least two values for mul");
486 self.stack.push(a * b);
487 }
488 pub fn peek(&self) -> Option<i64> {
490 self.stack.last().copied()
491 }
492 pub fn depth(&self) -> usize {
494 self.stack.len()
495 }
496}
497#[allow(dead_code)]
499pub struct Stopwatch {
500 start: std::time::Instant,
501 splits: Vec<f64>,
502}
503#[allow(dead_code)]
504impl Stopwatch {
505 pub fn start() -> Self {
507 Self {
508 start: std::time::Instant::now(),
509 splits: Vec::new(),
510 }
511 }
512 pub fn split(&mut self) {
514 self.splits.push(self.elapsed_ms());
515 }
516 pub fn elapsed_ms(&self) -> f64 {
518 self.start.elapsed().as_secs_f64() * 1000.0
519 }
520 pub fn splits(&self) -> &[f64] {
522 &self.splits
523 }
524 pub fn num_splits(&self) -> usize {
526 self.splits.len()
527 }
528}
529pub struct CacheManager {
531 pub(crate) whnf: WhnfCache,
532 pub(crate) defeq: DefEqCache,
533 pub(crate) infer: InferCache,
534}
535impl CacheManager {
536 pub fn new() -> Self {
538 CacheManager {
539 whnf: WhnfCache::new(1024, false),
540 defeq: DefEqCache::new(512),
541 infer: InferCache::new(256),
542 }
543 }
544 pub fn with_capacities(whnf_cap: usize, defeq_cap: usize, infer_cap: usize) -> Self {
546 CacheManager {
547 whnf: WhnfCache::new(whnf_cap, false),
548 defeq: DefEqCache::new(defeq_cap),
549 infer: InferCache::new(infer_cap),
550 }
551 }
552 pub fn whnf_mut(&mut self) -> &mut WhnfCache {
554 &mut self.whnf
555 }
556 pub fn defeq_mut(&mut self) -> &mut DefEqCache {
558 &mut self.defeq
559 }
560 pub fn infer_mut(&mut self) -> &mut InferCache {
562 &mut self.infer
563 }
564 pub fn clear_all(&mut self) {
566 self.whnf.clear();
567 self.defeq.clear();
568 self.infer.clear();
569 }
570 pub fn resize_all(&mut self, whnf_cap: usize, defeq_cap: usize, infer_cap: usize) {
572 self.whnf = WhnfCache::new(whnf_cap, self.whnf.is_transparent());
573 self.defeq = DefEqCache::new(defeq_cap);
574 self.infer = InferCache::new(infer_cap);
575 }
576 pub fn statistics(&self) -> CacheStatistics {
578 let (whnf_hits, whnf_misses) = self.whnf.stats();
579 let (defeq_hits, defeq_misses) = self.defeq.stats();
580 let (infer_hits, infer_misses) = self.infer.stats();
581 CacheStatistics {
582 whnf_hits,
583 whnf_misses,
584 whnf_hit_rate: self.whnf.hit_rate(),
585 defeq_hits,
586 defeq_misses,
587 defeq_hit_rate: self.defeq.hit_rate(),
588 infer_hits,
589 infer_misses,
590 infer_hit_rate: self.infer.hit_rate(),
591 }
592 }
593}
594#[derive(Clone, Debug, PartialEq, Eq)]
598pub enum SimplifiedExpr {
599 Var(String),
601 App(Box<SimplifiedExpr>, Box<SimplifiedExpr>),
603 Lambda(String, Box<SimplifiedExpr>),
605 Pi(String, Box<SimplifiedExpr>, Box<SimplifiedExpr>),
607}
608impl SimplifiedExpr {
609 pub fn hash(&self) -> u64 {
611 match self {
612 SimplifiedExpr::Var(name) => {
613 let mut bytes = vec![0u8];
614 bytes.extend_from_slice(name.as_bytes());
615 fnv1a_hash(&bytes)
616 }
617 SimplifiedExpr::App(f, arg) => {
618 let f_hash = f.hash();
619 let arg_hash = arg.hash();
620 let mut bytes = vec![1u8];
621 bytes.extend_from_slice(&f_hash.to_le_bytes());
622 bytes.extend_from_slice(&arg_hash.to_le_bytes());
623 fnv1a_hash(&bytes)
624 }
625 SimplifiedExpr::Lambda(name, body) => {
626 let body_hash = body.hash();
627 let mut bytes = vec![2u8];
628 bytes.extend_from_slice(name.as_bytes());
629 bytes.extend_from_slice(&body_hash.to_le_bytes());
630 fnv1a_hash(&bytes)
631 }
632 SimplifiedExpr::Pi(name, typ, body) => {
633 let typ_hash = typ.hash();
634 let body_hash = body.hash();
635 let mut bytes = vec![3u8];
636 bytes.extend_from_slice(name.as_bytes());
637 bytes.extend_from_slice(&typ_hash.to_le_bytes());
638 bytes.extend_from_slice(&body_hash.to_le_bytes());
639 fnv1a_hash(&bytes)
640 }
641 }
642 }
643}
644#[allow(dead_code)]
646pub struct WindowIterator<'a, T> {
647 pub(super) data: &'a [T],
648 pub(super) pos: usize,
649 pub(super) window: usize,
650}
651#[allow(dead_code)]
652impl<'a, T> WindowIterator<'a, T> {
653 pub fn new(data: &'a [T], window: usize) -> Self {
655 Self {
656 data,
657 pos: 0,
658 window,
659 }
660 }
661}
662#[allow(dead_code)]
664pub struct RewriteRuleSet {
665 rules: Vec<RewriteRule>,
666}
667#[allow(dead_code)]
668impl RewriteRuleSet {
669 pub fn new() -> Self {
671 Self { rules: Vec::new() }
672 }
673 pub fn add(&mut self, rule: RewriteRule) {
675 self.rules.push(rule);
676 }
677 pub fn len(&self) -> usize {
679 self.rules.len()
680 }
681 pub fn is_empty(&self) -> bool {
683 self.rules.is_empty()
684 }
685 pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
687 self.rules.iter().filter(|r| r.conditional).collect()
688 }
689 pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
691 self.rules.iter().filter(|r| !r.conditional).collect()
692 }
693 pub fn get(&self, name: &str) -> Option<&RewriteRule> {
695 self.rules.iter().find(|r| r.name == name)
696 }
697}
698pub struct LruCache<K: Clone + Eq + std::hash::Hash, V: Clone> {
700 capacity: usize,
701 map: HashMap<K, usize>,
702 nodes: Vec<Node<K, V>>,
703 head: Option<usize>,
704 tail: Option<usize>,
705 hits: u64,
706 misses: u64,
707}
708impl<K: Clone + Eq + std::hash::Hash, V: Clone> LruCache<K, V> {
709 pub fn new(capacity: usize) -> Self {
711 assert!(capacity > 0, "LRU cache capacity must be > 0");
712 LruCache {
713 capacity,
714 map: HashMap::new(),
715 nodes: Vec::new(),
716 head: None,
717 tail: None,
718 hits: 0,
719 misses: 0,
720 }
721 }
722 pub fn get(&mut self, key: &K) -> Option<V> {
724 if let Some(&idx) = self.map.get(key) {
725 self.hits += 1;
726 self.move_to_head(idx);
727 Some(self.nodes[idx].value.clone())
728 } else {
729 self.misses += 1;
730 None
731 }
732 }
733 pub fn insert(&mut self, key: K, value: V) {
735 if let Some(&idx) = self.map.get(&key) {
736 self.nodes[idx].value = value;
737 self.move_to_head(idx);
738 } else {
739 if self.nodes.len() >= self.capacity {
740 self.evict_lru();
741 }
742 let new_idx = self.nodes.len();
743 let node = Node {
744 key: key.clone(),
745 value,
746 prev: None,
747 next: self.head,
748 };
749 self.nodes.push(node);
750 self.map.insert(key, new_idx);
751 if let Some(old_head) = self.head {
752 self.nodes[old_head].prev = Some(new_idx);
753 }
754 self.head = Some(new_idx);
755 if self.tail.is_none() {
756 self.tail = Some(new_idx);
757 }
758 }
759 }
760 pub fn remove(&mut self, key: &K) -> Option<V> {
762 if let Some(&idx) = self.map.get(key) {
763 let node = &self.nodes[idx];
764 let prev = node.prev;
765 let next = node.next;
766 if let Some(p) = prev {
767 self.nodes[p].next = next;
768 } else {
769 self.tail = next;
770 }
771 if let Some(n) = next {
772 self.nodes[n].prev = prev;
773 } else {
774 self.head = prev;
775 }
776 self.map.remove(key);
777 Some(self.nodes[idx].value.clone())
778 } else {
779 None
780 }
781 }
782 pub fn contains_key(&self, key: &K) -> bool {
784 self.map.contains_key(key)
785 }
786 pub fn len(&self) -> usize {
788 self.map.len()
789 }
790 pub fn is_empty(&self) -> bool {
792 self.map.is_empty()
793 }
794 pub fn capacity(&self) -> usize {
796 self.capacity
797 }
798 pub fn clear(&mut self) {
800 self.map.clear();
801 self.nodes.clear();
802 self.head = None;
803 self.tail = None;
804 self.hits = 0;
805 self.misses = 0;
806 }
807 pub fn stats(&self) -> (u64, u64) {
809 (self.hits, self.misses)
810 }
811 pub fn hit_rate(&self) -> f64 {
813 let total = self.hits + self.misses;
814 if total == 0 {
815 0.0
816 } else {
817 (self.hits as f64 / total as f64) * 100.0
818 }
819 }
820 fn move_to_head(&mut self, idx: usize) {
821 if self.head == Some(idx) {
822 return;
823 }
824 let prev = self.nodes[idx].prev;
825 let next = self.nodes[idx].next;
826 if let Some(p) = prev {
827 self.nodes[p].next = next;
828 }
829 if let Some(n) = next {
830 self.nodes[n].prev = prev;
831 } else {
832 self.tail = prev;
833 }
834 self.nodes[idx].prev = None;
835 self.nodes[idx].next = self.head;
836 if let Some(old_head) = self.head {
837 self.nodes[old_head].prev = Some(idx);
838 }
839 self.head = Some(idx);
840 }
841 fn evict_lru(&mut self) {
842 if let Some(tail_idx) = self.tail {
843 let key = self.nodes[tail_idx].key.clone();
844 let prev = self.nodes[tail_idx].prev;
845 if let Some(p) = prev {
846 self.nodes[p].next = None;
847 self.head = Some(p);
848 } else {
849 self.head = None;
850 }
851 self.tail = prev;
852 self.map.remove(&key);
853 self.nodes.remove(tail_idx);
854 self.nodes.iter().enumerate().for_each(|(i, node)| {
855 *self
856 .map
857 .get_mut(&node.key)
858 .expect("node key must exist in map") = i;
859 });
860 }
861 }
862}
863pub struct BloomFilterApprox {
868 bits: Vec<bool>,
869 size: usize,
870}
871impl BloomFilterApprox {
872 pub fn new(size: usize) -> Self {
874 Self {
875 bits: vec![false; size],
876 size,
877 }
878 }
879 fn hash1(data: &[u8], size: usize) -> usize {
880 fnv1a_hash(data) as usize % size
881 }
882 fn hash2(data: &[u8], size: usize) -> usize {
883 let h = fnv1a_hash(data).wrapping_mul(0x9e3779b9_7f4a7c15);
884 h as usize % size
885 }
886 pub fn insert<T: AsRef<[u8]>>(&mut self, key: T) {
888 let bytes = key.as_ref();
889 let h1 = Self::hash1(bytes, self.size);
890 let h2 = Self::hash2(bytes, self.size);
891 self.bits[h1] = true;
892 self.bits[h2] = true;
893 }
894 pub fn might_contain<T: AsRef<[u8]>>(&self, key: T) -> bool {
896 let bytes = key.as_ref();
897 let h1 = Self::hash1(bytes, self.size);
898 let h2 = Self::hash2(bytes, self.size);
899 self.bits[h1] && self.bits[h2]
900 }
901 pub fn clear(&mut self) {
903 self.bits.iter_mut().for_each(|b| *b = false);
904 }
905 pub fn set_bit_count(&self) -> usize {
907 self.bits.iter().filter(|&&b| b).count()
908 }
909 pub fn size(&self) -> usize {
911 self.size
912 }
913}
914pub struct MultiLevelCache<K: Clone + Eq + std::hash::Hash, V: Clone> {
919 l1: LruCache<K, V>,
920 l2: LruCache<K, V>,
921 l1_hits: u64,
922 l2_hits: u64,
923 misses: u64,
924}
925impl<K: Clone + Eq + std::hash::Hash, V: Clone> MultiLevelCache<K, V> {
926 pub fn new(l1_cap: usize, l2_cap: usize) -> Self {
928 Self {
929 l1: LruCache::new(l1_cap),
930 l2: LruCache::new(l2_cap),
931 l1_hits: 0,
932 l2_hits: 0,
933 misses: 0,
934 }
935 }
936 pub fn get(&mut self, key: &K) -> Option<V> {
938 if let Some(v) = self.l1.get(key) {
939 self.l1_hits += 1;
940 return Some(v);
941 }
942 if let Some(v) = self.l2.get(key) {
943 self.l2_hits += 1;
944 self.l1.insert(key.clone(), v.clone());
945 return Some(v);
946 }
947 self.misses += 1;
948 None
949 }
950 pub fn insert(&mut self, key: K, value: V) {
952 self.l1.insert(key.clone(), value.clone());
953 self.l2.insert(key, value);
954 }
955 pub fn insert_l2_only(&mut self, key: K, value: V) {
957 self.l2.insert(key, value);
958 }
959 pub fn clear_l1(&mut self) {
961 self.l1.clear();
962 }
963 pub fn clear_all(&mut self) {
965 self.l1.clear();
966 self.l2.clear();
967 self.l1_hits = 0;
968 self.l2_hits = 0;
969 self.misses = 0;
970 }
971 pub fn l1_hits(&self) -> u64 {
973 self.l1_hits
974 }
975 pub fn l2_hits(&self) -> u64 {
977 self.l2_hits
978 }
979 pub fn misses(&self) -> u64 {
981 self.misses
982 }
983 pub fn total_requests(&self) -> u64 {
985 self.l1_hits + self.l2_hits + self.misses
986 }
987 pub fn hit_rate(&self) -> f64 {
989 let total = self.total_requests();
990 if total == 0 {
991 0.0
992 } else {
993 ((self.l1_hits + self.l2_hits) as f64 / total as f64) * 100.0
994 }
995 }
996}
997pub struct DefEqCache {
999 pub(crate) cache: LruCache<(u64, u64), bool>,
1000}
1001impl DefEqCache {
1002 pub fn new(capacity: usize) -> Self {
1004 DefEqCache {
1005 cache: LruCache::new(capacity),
1006 }
1007 }
1008 pub fn check_cache(&mut self, expr1: &SimplifiedExpr, expr2: &SimplifiedExpr) -> Option<bool> {
1010 let hash1 = expr1.hash();
1011 let hash2 = expr2.hash();
1012 if let Some(result) = self.cache.get(&(hash1, hash2)) {
1013 return Some(result);
1014 }
1015 if let Some(result) = self.cache.get(&(hash2, hash1)) {
1016 return Some(result);
1017 }
1018 None
1019 }
1020 pub fn store_result(&mut self, expr1: &SimplifiedExpr, expr2: &SimplifiedExpr, result: bool) {
1022 let hash1 = expr1.hash();
1023 let hash2 = expr2.hash();
1024 self.cache.insert((hash1, hash2), result);
1025 self.cache.insert((hash2, hash1), result);
1026 }
1027 pub fn clear(&mut self) {
1029 self.cache.clear();
1030 }
1031 pub fn stats(&self) -> (u64, u64) {
1033 self.cache.stats()
1034 }
1035 pub fn hit_rate(&self) -> f64 {
1037 self.cache.hit_rate()
1038 }
1039}
1040#[allow(dead_code)]
1042pub struct FocusStack<T> {
1043 items: Vec<T>,
1044}
1045#[allow(dead_code)]
1046impl<T> FocusStack<T> {
1047 pub fn new() -> Self {
1049 Self { items: Vec::new() }
1050 }
1051 pub fn focus(&mut self, item: T) {
1053 self.items.push(item);
1054 }
1055 pub fn blur(&mut self) -> Option<T> {
1057 self.items.pop()
1058 }
1059 pub fn current(&self) -> Option<&T> {
1061 self.items.last()
1062 }
1063 pub fn depth(&self) -> usize {
1065 self.items.len()
1066 }
1067 pub fn is_empty(&self) -> bool {
1069 self.items.is_empty()
1070 }
1071}
1072#[allow(dead_code)]
1074pub struct StatSummary {
1075 count: u64,
1076 sum: f64,
1077 min: f64,
1078 max: f64,
1079}
1080#[allow(dead_code)]
1081impl StatSummary {
1082 pub fn new() -> Self {
1084 Self {
1085 count: 0,
1086 sum: 0.0,
1087 min: f64::INFINITY,
1088 max: f64::NEG_INFINITY,
1089 }
1090 }
1091 pub fn record(&mut self, val: f64) {
1093 self.count += 1;
1094 self.sum += val;
1095 if val < self.min {
1096 self.min = val;
1097 }
1098 if val > self.max {
1099 self.max = val;
1100 }
1101 }
1102 pub fn mean(&self) -> Option<f64> {
1104 if self.count == 0 {
1105 None
1106 } else {
1107 Some(self.sum / self.count as f64)
1108 }
1109 }
1110 pub fn min(&self) -> Option<f64> {
1112 if self.count == 0 {
1113 None
1114 } else {
1115 Some(self.min)
1116 }
1117 }
1118 pub fn max(&self) -> Option<f64> {
1120 if self.count == 0 {
1121 None
1122 } else {
1123 Some(self.max)
1124 }
1125 }
1126 pub fn count(&self) -> u64 {
1128 self.count
1129 }
1130}
1131#[derive(Clone, Debug)]
1132struct TtlEntry<V> {
1133 value: V,
1134 expires_at: u64,
1135}
1136#[allow(dead_code)]
1138pub struct SparseVec<T: Default + Clone + PartialEq> {
1139 entries: std::collections::HashMap<usize, T>,
1140 default_: T,
1141 logical_len: usize,
1142}
1143#[allow(dead_code)]
1144impl<T: Default + Clone + PartialEq> SparseVec<T> {
1145 pub fn new(len: usize) -> Self {
1147 Self {
1148 entries: std::collections::HashMap::new(),
1149 default_: T::default(),
1150 logical_len: len,
1151 }
1152 }
1153 pub fn set(&mut self, idx: usize, val: T) {
1155 if val == self.default_ {
1156 self.entries.remove(&idx);
1157 } else {
1158 self.entries.insert(idx, val);
1159 }
1160 }
1161 pub fn get(&self, idx: usize) -> &T {
1163 self.entries.get(&idx).unwrap_or(&self.default_)
1164 }
1165 pub fn len(&self) -> usize {
1167 self.logical_len
1168 }
1169 pub fn is_empty(&self) -> bool {
1171 self.len() == 0
1172 }
1173 pub fn nnz(&self) -> usize {
1175 self.entries.len()
1176 }
1177}
1178#[allow(dead_code)]
1180#[allow(missing_docs)]
1181pub struct RewriteRule {
1182 pub name: String,
1184 pub lhs: String,
1186 pub rhs: String,
1188 pub conditional: bool,
1190}
1191#[allow(dead_code)]
1192impl RewriteRule {
1193 pub fn unconditional(
1195 name: impl Into<String>,
1196 lhs: impl Into<String>,
1197 rhs: impl Into<String>,
1198 ) -> Self {
1199 Self {
1200 name: name.into(),
1201 lhs: lhs.into(),
1202 rhs: rhs.into(),
1203 conditional: false,
1204 }
1205 }
1206 pub fn conditional(
1208 name: impl Into<String>,
1209 lhs: impl Into<String>,
1210 rhs: impl Into<String>,
1211 ) -> Self {
1212 Self {
1213 name: name.into(),
1214 lhs: lhs.into(),
1215 rhs: rhs.into(),
1216 conditional: true,
1217 }
1218 }
1219 pub fn display(&self) -> String {
1221 format!("{}: {} → {}", self.name, self.lhs, self.rhs)
1222 }
1223}
1224#[derive(Clone, Debug)]
1228pub struct CacheStatistics {
1229 pub whnf_hits: u64,
1231 pub whnf_misses: u64,
1233 pub whnf_hit_rate: f64,
1235 pub defeq_hits: u64,
1237 pub defeq_misses: u64,
1239 pub defeq_hit_rate: f64,
1241 pub infer_hits: u64,
1243 pub infer_misses: u64,
1245 pub infer_hit_rate: f64,
1247}
1248impl CacheStatistics {
1249 pub fn total_hits(&self) -> u64 {
1251 self.whnf_hits + self.defeq_hits + self.infer_hits
1252 }
1253 pub fn total_misses(&self) -> u64 {
1255 self.whnf_misses + self.defeq_misses + self.infer_misses
1256 }
1257 pub fn overall_hit_rate(&self) -> f64 {
1259 let total = self.total_hits() + self.total_misses();
1260 if total == 0 {
1261 0.0
1262 } else {
1263 (self.total_hits() as f64 / total as f64) * 100.0
1264 }
1265 }
1266}
1267#[allow(dead_code)]
1269pub struct FlatSubstitution {
1270 pairs: Vec<(String, String)>,
1271}
1272#[allow(dead_code)]
1273impl FlatSubstitution {
1274 pub fn new() -> Self {
1276 Self { pairs: Vec::new() }
1277 }
1278 pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
1280 self.pairs.push((from.into(), to.into()));
1281 }
1282 pub fn apply(&self, s: &str) -> String {
1284 let mut result = s.to_string();
1285 for (from, to) in &self.pairs {
1286 result = result.replace(from.as_str(), to.as_str());
1287 }
1288 result
1289 }
1290 pub fn len(&self) -> usize {
1292 self.pairs.len()
1293 }
1294 pub fn is_empty(&self) -> bool {
1296 self.pairs.is_empty()
1297 }
1298}
1299#[allow(dead_code)]
1301pub struct NonEmptyVec<T> {
1302 head: T,
1303 tail: Vec<T>,
1304}
1305#[allow(dead_code)]
1306impl<T> NonEmptyVec<T> {
1307 pub fn singleton(val: T) -> Self {
1309 Self {
1310 head: val,
1311 tail: Vec::new(),
1312 }
1313 }
1314 pub fn push(&mut self, val: T) {
1316 self.tail.push(val);
1317 }
1318 pub fn first(&self) -> &T {
1320 &self.head
1321 }
1322 pub fn last(&self) -> &T {
1324 self.tail.last().unwrap_or(&self.head)
1325 }
1326 pub fn len(&self) -> usize {
1328 1 + self.tail.len()
1329 }
1330 pub fn is_empty(&self) -> bool {
1332 self.len() == 0
1333 }
1334 pub fn to_vec(&self) -> Vec<&T> {
1336 let mut v = vec![&self.head];
1337 v.extend(self.tail.iter());
1338 v
1339 }
1340}
1341pub struct InferCache {
1343 pub(crate) cache: LruCache<u64, SimplifiedExpr>,
1344}
1345impl InferCache {
1346 pub fn new(capacity: usize) -> Self {
1348 InferCache {
1349 cache: LruCache::new(capacity),
1350 }
1351 }
1352 pub fn lookup(&mut self, expr: &SimplifiedExpr) -> Option<SimplifiedExpr> {
1354 let hash = expr.hash();
1355 self.cache.get(&hash)
1356 }
1357 pub fn store(&mut self, expr: &SimplifiedExpr, inferred_type: SimplifiedExpr) {
1359 let hash = expr.hash();
1360 self.cache.insert(hash, inferred_type);
1361 }
1362 pub fn clear(&mut self) {
1364 self.cache.clear();
1365 }
1366 pub fn stats(&self) -> (u64, u64) {
1368 self.cache.stats()
1369 }
1370 pub fn hit_rate(&self) -> f64 {
1372 self.cache.hit_rate()
1373 }
1374 pub fn len(&self) -> usize {
1376 self.cache.len()
1377 }
1378 pub fn is_empty(&self) -> bool {
1380 self.cache.is_empty()
1381 }
1382}
1383#[allow(dead_code)]
1385pub struct StringPool {
1386 free: Vec<String>,
1387}
1388#[allow(dead_code)]
1389impl StringPool {
1390 pub fn new() -> Self {
1392 Self { free: Vec::new() }
1393 }
1394 pub fn take(&mut self) -> String {
1396 self.free.pop().unwrap_or_default()
1397 }
1398 pub fn give(&mut self, mut s: String) {
1400 s.clear();
1401 self.free.push(s);
1402 }
1403 pub fn free_count(&self) -> usize {
1405 self.free.len()
1406 }
1407}
1408pub struct WhnfCache {
1410 pub(crate) cache: LruCache<u64, SimplifiedExpr>,
1411 transparency_mode: bool,
1412}
1413impl WhnfCache {
1414 pub fn new(capacity: usize, transparency_mode: bool) -> Self {
1416 WhnfCache {
1417 cache: LruCache::new(capacity),
1418 transparency_mode,
1419 }
1420 }
1421 pub fn lookup(&mut self, expr: &SimplifiedExpr) -> Option<SimplifiedExpr> {
1423 if !self.transparency_mode {
1424 let hash = expr.hash();
1425 self.cache.get(&hash)
1426 } else {
1427 None
1428 }
1429 }
1430 pub fn store(&mut self, expr: &SimplifiedExpr, whnf: SimplifiedExpr) {
1432 if !self.transparency_mode {
1433 let hash = expr.hash();
1434 self.cache.insert(hash, whnf);
1435 }
1436 }
1437 pub fn clear(&mut self) {
1439 self.cache.clear();
1440 }
1441 pub fn stats(&self) -> (u64, u64) {
1443 self.cache.stats()
1444 }
1445 pub fn hit_rate(&self) -> f64 {
1447 self.cache.hit_rate()
1448 }
1449 pub fn set_transparency(&mut self, mode: bool) {
1451 self.transparency_mode = mode;
1452 if mode {
1453 self.cache.clear();
1454 }
1455 }
1456 pub fn is_transparent(&self) -> bool {
1458 self.transparency_mode
1459 }
1460}
1461#[allow(dead_code)]
1463pub struct VersionedRecord<T: Clone> {
1464 history: Vec<T>,
1465}
1466#[allow(dead_code)]
1467impl<T: Clone> VersionedRecord<T> {
1468 pub fn new(initial: T) -> Self {
1470 Self {
1471 history: vec![initial],
1472 }
1473 }
1474 pub fn update(&mut self, val: T) {
1476 self.history.push(val);
1477 }
1478 pub fn current(&self) -> &T {
1480 self.history
1481 .last()
1482 .expect("VersionedRecord history is always non-empty after construction")
1483 }
1484 pub fn at_version(&self, n: usize) -> Option<&T> {
1486 self.history.get(n)
1487 }
1488 pub fn version(&self) -> usize {
1490 self.history.len() - 1
1491 }
1492 pub fn has_history(&self) -> bool {
1494 self.history.len() > 1
1495 }
1496}
1497pub struct TtlCache<K: Clone + Eq + std::hash::Hash, V: Clone> {
1502 entries: HashMap<K, TtlEntry<V>>,
1503 step: u64,
1505 default_ttl: u64,
1507}
1508impl<K: Clone + Eq + std::hash::Hash, V: Clone> TtlCache<K, V> {
1509 pub fn new(default_ttl: u64) -> Self {
1511 Self {
1512 entries: HashMap::new(),
1513 step: 0,
1514 default_ttl,
1515 }
1516 }
1517 pub fn tick(&mut self) {
1519 self.step += 1;
1520 }
1521 pub fn tick_n(&mut self, n: u64) {
1523 self.step += n;
1524 }
1525 pub fn insert(&mut self, key: K, value: V) {
1527 self.entries.insert(
1528 key,
1529 TtlEntry {
1530 value,
1531 expires_at: self.step + self.default_ttl,
1532 },
1533 );
1534 }
1535 pub fn insert_with_ttl(&mut self, key: K, value: V, ttl: u64) {
1537 self.entries.insert(
1538 key,
1539 TtlEntry {
1540 value,
1541 expires_at: self.step + ttl,
1542 },
1543 );
1544 }
1545 pub fn get(&self, key: &K) -> Option<V> {
1547 self.entries.get(key).and_then(|e| {
1548 if self.step < e.expires_at {
1549 Some(e.value.clone())
1550 } else {
1551 None
1552 }
1553 })
1554 }
1555 pub fn purge_expired(&mut self) {
1557 let step = self.step;
1558 self.entries.retain(|_, e| step < e.expires_at);
1559 }
1560 pub fn len(&self) -> usize {
1562 self.entries.len()
1563 }
1564 pub fn is_empty(&self) -> bool {
1566 self.entries.is_empty()
1567 }
1568 pub fn current_step(&self) -> u64 {
1570 self.step
1571 }
1572 pub fn clear(&mut self) {
1574 self.entries.clear();
1575 }
1576}
1577#[allow(dead_code)]
1579pub struct WriteOnce<T> {
1580 value: std::cell::Cell<Option<T>>,
1581}
1582#[allow(dead_code)]
1583impl<T: Copy> WriteOnce<T> {
1584 pub fn new() -> Self {
1586 Self {
1587 value: std::cell::Cell::new(None),
1588 }
1589 }
1590 pub fn write(&self, val: T) -> bool {
1592 if self.value.get().is_some() {
1593 return false;
1594 }
1595 self.value.set(Some(val));
1596 true
1597 }
1598 pub fn read(&self) -> Option<T> {
1600 self.value.get()
1601 }
1602 pub fn is_written(&self) -> bool {
1604 self.value.get().is_some()
1605 }
1606}
1607#[derive(Clone, Debug)]
1609struct Node<K, V> {
1610 key: K,
1611 value: V,
1612 prev: Option<usize>,
1613 next: Option<usize>,
1614}
1615#[allow(dead_code)]
1617pub struct LabelSet {
1618 labels: Vec<String>,
1619}
1620#[allow(dead_code)]
1621impl LabelSet {
1622 pub fn new() -> Self {
1624 Self { labels: Vec::new() }
1625 }
1626 pub fn add(&mut self, label: impl Into<String>) {
1628 let s = label.into();
1629 if !self.labels.contains(&s) {
1630 self.labels.push(s);
1631 }
1632 }
1633 pub fn has(&self, label: &str) -> bool {
1635 self.labels.iter().any(|l| l == label)
1636 }
1637 pub fn count(&self) -> usize {
1639 self.labels.len()
1640 }
1641 pub fn all(&self) -> &[String] {
1643 &self.labels
1644 }
1645}
1646#[allow(dead_code)]
1648pub struct TransitiveClosure {
1649 adj: Vec<Vec<usize>>,
1650 n: usize,
1651}
1652#[allow(dead_code)]
1653impl TransitiveClosure {
1654 pub fn new(n: usize) -> Self {
1656 Self {
1657 adj: vec![Vec::new(); n],
1658 n,
1659 }
1660 }
1661 pub fn add_edge(&mut self, from: usize, to: usize) {
1663 if from < self.n {
1664 self.adj[from].push(to);
1665 }
1666 }
1667 pub fn reachable_from(&self, start: usize) -> Vec<usize> {
1669 let mut visited = vec![false; self.n];
1670 let mut queue = std::collections::VecDeque::new();
1671 queue.push_back(start);
1672 while let Some(node) = queue.pop_front() {
1673 if node >= self.n || visited[node] {
1674 continue;
1675 }
1676 visited[node] = true;
1677 for &next in &self.adj[node] {
1678 queue.push_back(next);
1679 }
1680 }
1681 (0..self.n).filter(|&i| visited[i]).collect()
1682 }
1683 pub fn can_reach(&self, from: usize, to: usize) -> bool {
1685 self.reachable_from(from).contains(&to)
1686 }
1687}
1688#[allow(dead_code)]
1690pub struct SmallMap<K: Ord + Clone, V: Clone> {
1691 entries: Vec<(K, V)>,
1692}
1693#[allow(dead_code)]
1694impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
1695 pub fn new() -> Self {
1697 Self {
1698 entries: Vec::new(),
1699 }
1700 }
1701 pub fn insert(&mut self, key: K, val: V) {
1703 match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
1704 Ok(i) => self.entries[i].1 = val,
1705 Err(i) => self.entries.insert(i, (key, val)),
1706 }
1707 }
1708 pub fn get(&self, key: &K) -> Option<&V> {
1710 self.entries
1711 .binary_search_by_key(&key, |(k, _)| k)
1712 .ok()
1713 .map(|i| &self.entries[i].1)
1714 }
1715 pub fn len(&self) -> usize {
1717 self.entries.len()
1718 }
1719 pub fn is_empty(&self) -> bool {
1721 self.entries.is_empty()
1722 }
1723 pub fn keys(&self) -> Vec<&K> {
1725 self.entries.iter().map(|(k, _)| k).collect()
1726 }
1727 pub fn values(&self) -> Vec<&V> {
1729 self.entries.iter().map(|(_, v)| v).collect()
1730 }
1731}