1use super::functions::*;
6use crate::{Expr, FVarId};
7use std::collections::HashMap;
8
9#[allow(dead_code)]
11pub struct TransformStat {
12 before: StatSummary,
13 after: StatSummary,
14}
15#[allow(dead_code)]
16impl TransformStat {
17 pub fn new() -> Self {
19 Self {
20 before: StatSummary::new(),
21 after: StatSummary::new(),
22 }
23 }
24 pub fn record_before(&mut self, v: f64) {
26 self.before.record(v);
27 }
28 pub fn record_after(&mut self, v: f64) {
30 self.after.record(v);
31 }
32 pub fn mean_ratio(&self) -> Option<f64> {
34 let b = self.before.mean()?;
35 let a = self.after.mean()?;
36 if b.abs() < f64::EPSILON {
37 return None;
38 }
39 Some(a / b)
40 }
41}
42#[allow(dead_code)]
44pub struct FocusStack<T> {
45 items: Vec<T>,
46}
47#[allow(dead_code)]
48impl<T> FocusStack<T> {
49 pub fn new() -> Self {
51 Self { items: Vec::new() }
52 }
53 pub fn focus(&mut self, item: T) {
55 self.items.push(item);
56 }
57 pub fn blur(&mut self) -> Option<T> {
59 self.items.pop()
60 }
61 pub fn current(&self) -> Option<&T> {
63 self.items.last()
64 }
65 pub fn depth(&self) -> usize {
67 self.items.len()
68 }
69 pub fn is_empty(&self) -> bool {
71 self.items.is_empty()
72 }
73}
74#[allow(dead_code)]
76pub struct PathBuf {
77 components: Vec<String>,
78}
79#[allow(dead_code)]
80impl PathBuf {
81 pub fn new() -> Self {
83 Self {
84 components: Vec::new(),
85 }
86 }
87 pub fn push(&mut self, comp: impl Into<String>) {
89 self.components.push(comp.into());
90 }
91 pub fn pop(&mut self) {
93 self.components.pop();
94 }
95 pub fn as_str(&self) -> String {
97 self.components.join("/")
98 }
99 pub fn depth(&self) -> usize {
101 self.components.len()
102 }
103 pub fn clear(&mut self) {
105 self.components.clear();
106 }
107}
108#[allow(dead_code)]
110pub struct TokenBucket {
111 capacity: u64,
112 tokens: u64,
113 refill_per_ms: u64,
114 last_refill: std::time::Instant,
115}
116#[allow(dead_code)]
117impl TokenBucket {
118 pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
120 Self {
121 capacity,
122 tokens: capacity,
123 refill_per_ms,
124 last_refill: std::time::Instant::now(),
125 }
126 }
127 pub fn try_consume(&mut self, n: u64) -> bool {
129 self.refill();
130 if self.tokens >= n {
131 self.tokens -= n;
132 true
133 } else {
134 false
135 }
136 }
137 fn refill(&mut self) {
138 let now = std::time::Instant::now();
139 let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
140 if elapsed_ms > 0 {
141 let new_tokens = elapsed_ms * self.refill_per_ms;
142 self.tokens = (self.tokens + new_tokens).min(self.capacity);
143 self.last_refill = now;
144 }
145 }
146 pub fn available(&self) -> u64 {
148 self.tokens
149 }
150 pub fn capacity(&self) -> u64 {
152 self.capacity
153 }
154}
155#[allow(dead_code)]
157pub struct RawFnPtr {
158 ptr: usize,
160 arity: usize,
161 name: String,
162}
163#[allow(dead_code)]
164impl RawFnPtr {
165 pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
167 Self {
168 ptr,
169 arity,
170 name: name.into(),
171 }
172 }
173 pub fn arity(&self) -> usize {
175 self.arity
176 }
177 pub fn name(&self) -> &str {
179 &self.name
180 }
181 pub fn raw(&self) -> usize {
183 self.ptr
184 }
185}
186#[allow(dead_code)]
188pub enum Either2<A, B> {
189 First(A),
191 Second(B),
193}
194#[allow(dead_code)]
195impl<A, B> Either2<A, B> {
196 pub fn is_first(&self) -> bool {
198 matches!(self, Either2::First(_))
199 }
200 pub fn is_second(&self) -> bool {
202 matches!(self, Either2::Second(_))
203 }
204 pub fn first(self) -> Option<A> {
206 match self {
207 Either2::First(a) => Some(a),
208 _ => None,
209 }
210 }
211 pub fn second(self) -> Option<B> {
213 match self {
214 Either2::Second(b) => Some(b),
215 _ => None,
216 }
217 }
218 pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
220 match self {
221 Either2::First(a) => Either2::First(f(a)),
222 Either2::Second(b) => Either2::Second(b),
223 }
224 }
225}
226#[allow(dead_code)]
228pub struct SlidingSum {
229 window: Vec<f64>,
230 capacity: usize,
231 pos: usize,
232 sum: f64,
233 count: usize,
234}
235#[allow(dead_code)]
236impl SlidingSum {
237 pub fn new(capacity: usize) -> Self {
239 Self {
240 window: vec![0.0; capacity],
241 capacity,
242 pos: 0,
243 sum: 0.0,
244 count: 0,
245 }
246 }
247 pub fn push(&mut self, val: f64) {
249 let oldest = self.window[self.pos];
250 self.sum -= oldest;
251 self.sum += val;
252 self.window[self.pos] = val;
253 self.pos = (self.pos + 1) % self.capacity;
254 if self.count < self.capacity {
255 self.count += 1;
256 }
257 }
258 pub fn sum(&self) -> f64 {
260 self.sum
261 }
262 pub fn mean(&self) -> Option<f64> {
264 if self.count == 0 {
265 None
266 } else {
267 Some(self.sum / self.count as f64)
268 }
269 }
270 pub fn count(&self) -> usize {
272 self.count
273 }
274}
275#[allow(dead_code)]
277pub struct WriteOnce<T> {
278 value: std::cell::Cell<Option<T>>,
279}
280#[allow(dead_code)]
281impl<T: Copy> WriteOnce<T> {
282 pub fn new() -> Self {
284 Self {
285 value: std::cell::Cell::new(None),
286 }
287 }
288 pub fn write(&self, val: T) -> bool {
290 if self.value.get().is_some() {
291 return false;
292 }
293 self.value.set(Some(val));
294 true
295 }
296 pub fn read(&self) -> Option<T> {
298 self.value.get()
299 }
300 pub fn is_written(&self) -> bool {
302 self.value.get().is_some()
303 }
304}
305#[allow(dead_code)]
307pub struct StackCalc {
308 stack: Vec<i64>,
309}
310#[allow(dead_code)]
311impl StackCalc {
312 pub fn new() -> Self {
314 Self { stack: Vec::new() }
315 }
316 pub fn push(&mut self, n: i64) {
318 self.stack.push(n);
319 }
320 pub fn add(&mut self) {
322 let b = self
323 .stack
324 .pop()
325 .expect("stack must have at least two values for add");
326 let a = self
327 .stack
328 .pop()
329 .expect("stack must have at least two values for add");
330 self.stack.push(a + b);
331 }
332 pub fn sub(&mut self) {
334 let b = self
335 .stack
336 .pop()
337 .expect("stack must have at least two values for sub");
338 let a = self
339 .stack
340 .pop()
341 .expect("stack must have at least two values for sub");
342 self.stack.push(a - b);
343 }
344 pub fn mul(&mut self) {
346 let b = self
347 .stack
348 .pop()
349 .expect("stack must have at least two values for mul");
350 let a = self
351 .stack
352 .pop()
353 .expect("stack must have at least two values for mul");
354 self.stack.push(a * b);
355 }
356 pub fn peek(&self) -> Option<i64> {
358 self.stack.last().copied()
359 }
360 pub fn depth(&self) -> usize {
362 self.stack.len()
363 }
364}
365#[allow(dead_code)]
367pub struct StringPool {
368 free: Vec<String>,
369}
370#[allow(dead_code)]
371impl StringPool {
372 pub fn new() -> Self {
374 Self { free: Vec::new() }
375 }
376 pub fn take(&mut self) -> String {
378 self.free.pop().unwrap_or_default()
379 }
380 pub fn give(&mut self, mut s: String) {
382 s.clear();
383 self.free.push(s);
384 }
385 pub fn free_count(&self) -> usize {
387 self.free.len()
388 }
389}
390#[allow(dead_code)]
392pub struct NonEmptyVec<T> {
393 head: T,
394 tail: Vec<T>,
395}
396#[allow(dead_code)]
397impl<T> NonEmptyVec<T> {
398 pub fn singleton(val: T) -> Self {
400 Self {
401 head: val,
402 tail: Vec::new(),
403 }
404 }
405 pub fn push(&mut self, val: T) {
407 self.tail.push(val);
408 }
409 pub fn first(&self) -> &T {
411 &self.head
412 }
413 pub fn last(&self) -> &T {
415 self.tail.last().unwrap_or(&self.head)
416 }
417 pub fn len(&self) -> usize {
419 1 + self.tail.len()
420 }
421 pub fn is_empty(&self) -> bool {
423 self.len() == 0
424 }
425 pub fn to_vec(&self) -> Vec<&T> {
427 let mut v = vec![&self.head];
428 v.extend(self.tail.iter());
429 v
430 }
431}
432#[derive(Debug, Clone, Default, PartialEq, Eq)]
434pub struct SubstStats {
435 pub bvar_hits: usize,
437 pub bvar_misses: usize,
439 pub fvar_hits: usize,
441 pub nodes_visited: usize,
443}
444impl SubstStats {
445 pub fn merge(&mut self, other: &SubstStats) {
447 self.bvar_hits += other.bvar_hits;
448 self.bvar_misses += other.bvar_misses;
449 self.fvar_hits += other.fvar_hits;
450 self.nodes_visited += other.nodes_visited;
451 }
452 pub fn total_substs(&self) -> usize {
454 self.bvar_hits + self.fvar_hits
455 }
456}
457#[allow(dead_code)]
459pub struct ConfigNode {
460 key: String,
461 value: Option<String>,
462 children: Vec<ConfigNode>,
463}
464#[allow(dead_code)]
465impl ConfigNode {
466 pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
468 Self {
469 key: key.into(),
470 value: Some(value.into()),
471 children: Vec::new(),
472 }
473 }
474 pub fn section(key: impl Into<String>) -> Self {
476 Self {
477 key: key.into(),
478 value: None,
479 children: Vec::new(),
480 }
481 }
482 pub fn add_child(&mut self, child: ConfigNode) {
484 self.children.push(child);
485 }
486 pub fn key(&self) -> &str {
488 &self.key
489 }
490 pub fn value(&self) -> Option<&str> {
492 self.value.as_deref()
493 }
494 pub fn num_children(&self) -> usize {
496 self.children.len()
497 }
498 pub fn lookup(&self, path: &str) -> Option<&str> {
500 let mut parts = path.splitn(2, '.');
501 let head = parts.next()?;
502 let tail = parts.next();
503 if head != self.key {
504 return None;
505 }
506 match tail {
507 None => self.value.as_deref(),
508 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
509 }
510 }
511 fn lookup_relative(&self, path: &str) -> Option<&str> {
512 let mut parts = path.splitn(2, '.');
513 let head = parts.next()?;
514 let tail = parts.next();
515 if head != self.key {
516 return None;
517 }
518 match tail {
519 None => self.value.as_deref(),
520 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
521 }
522 }
523}
524#[allow(dead_code)]
526pub struct StatSummary {
527 count: u64,
528 sum: f64,
529 min: f64,
530 max: f64,
531}
532#[allow(dead_code)]
533impl StatSummary {
534 pub fn new() -> Self {
536 Self {
537 count: 0,
538 sum: 0.0,
539 min: f64::INFINITY,
540 max: f64::NEG_INFINITY,
541 }
542 }
543 pub fn record(&mut self, val: f64) {
545 self.count += 1;
546 self.sum += val;
547 if val < self.min {
548 self.min = val;
549 }
550 if val > self.max {
551 self.max = val;
552 }
553 }
554 pub fn mean(&self) -> Option<f64> {
556 if self.count == 0 {
557 None
558 } else {
559 Some(self.sum / self.count as f64)
560 }
561 }
562 pub fn min(&self) -> Option<f64> {
564 if self.count == 0 {
565 None
566 } else {
567 Some(self.min)
568 }
569 }
570 pub fn max(&self) -> Option<f64> {
572 if self.count == 0 {
573 None
574 } else {
575 Some(self.max)
576 }
577 }
578 pub fn count(&self) -> u64 {
580 self.count
581 }
582}
583#[allow(dead_code)]
585pub struct VersionedRecord<T: Clone> {
586 history: Vec<T>,
587}
588#[allow(dead_code)]
589impl<T: Clone> VersionedRecord<T> {
590 pub fn new(initial: T) -> Self {
592 Self {
593 history: vec![initial],
594 }
595 }
596 pub fn update(&mut self, val: T) {
598 self.history.push(val);
599 }
600 pub fn current(&self) -> &T {
602 self.history
603 .last()
604 .expect("VersionedRecord history is always non-empty after construction")
605 }
606 pub fn at_version(&self, n: usize) -> Option<&T> {
608 self.history.get(n)
609 }
610 pub fn version(&self) -> usize {
612 self.history.len() - 1
613 }
614 pub fn has_history(&self) -> bool {
616 self.history.len() > 1
617 }
618}
619#[allow(dead_code)]
621pub struct TransitiveClosure {
622 adj: Vec<Vec<usize>>,
623 n: usize,
624}
625#[allow(dead_code)]
626impl TransitiveClosure {
627 pub fn new(n: usize) -> Self {
629 Self {
630 adj: vec![Vec::new(); n],
631 n,
632 }
633 }
634 pub fn add_edge(&mut self, from: usize, to: usize) {
636 if from < self.n {
637 self.adj[from].push(to);
638 }
639 }
640 pub fn reachable_from(&self, start: usize) -> Vec<usize> {
642 let mut visited = vec![false; self.n];
643 let mut queue = std::collections::VecDeque::new();
644 queue.push_back(start);
645 while let Some(node) = queue.pop_front() {
646 if node >= self.n || visited[node] {
647 continue;
648 }
649 visited[node] = true;
650 for &next in &self.adj[node] {
651 queue.push_back(next);
652 }
653 }
654 (0..self.n).filter(|&i| visited[i]).collect()
655 }
656 pub fn can_reach(&self, from: usize, to: usize) -> bool {
658 self.reachable_from(from).contains(&to)
659 }
660}
661#[allow(dead_code)]
663#[allow(missing_docs)]
664pub struct RewriteRule {
665 pub name: String,
667 pub lhs: String,
669 pub rhs: String,
671 pub conditional: bool,
673}
674#[allow(dead_code)]
675impl RewriteRule {
676 pub fn unconditional(
678 name: impl Into<String>,
679 lhs: impl Into<String>,
680 rhs: impl Into<String>,
681 ) -> Self {
682 Self {
683 name: name.into(),
684 lhs: lhs.into(),
685 rhs: rhs.into(),
686 conditional: false,
687 }
688 }
689 pub fn conditional(
691 name: impl Into<String>,
692 lhs: impl Into<String>,
693 rhs: impl Into<String>,
694 ) -> Self {
695 Self {
696 name: name.into(),
697 lhs: lhs.into(),
698 rhs: rhs.into(),
699 conditional: true,
700 }
701 }
702 pub fn display(&self) -> String {
704 format!("{}: {} → {}", self.name, self.lhs, self.rhs)
705 }
706}
707#[allow(dead_code)]
709pub struct WindowIterator<'a, T> {
710 pub(super) data: &'a [T],
711 pub(super) pos: usize,
712 pub(super) window: usize,
713}
714#[allow(dead_code)]
715impl<'a, T> WindowIterator<'a, T> {
716 pub fn new(data: &'a [T], window: usize) -> Self {
718 Self {
719 data,
720 pos: 0,
721 window,
722 }
723 }
724}
725#[allow(dead_code)]
727pub struct FlatSubstitution {
728 pairs: Vec<(String, String)>,
729}
730#[allow(dead_code)]
731impl FlatSubstitution {
732 pub fn new() -> Self {
734 Self { pairs: Vec::new() }
735 }
736 pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
738 self.pairs.push((from.into(), to.into()));
739 }
740 pub fn apply(&self, s: &str) -> String {
742 let mut result = s.to_string();
743 for (from, to) in &self.pairs {
744 result = result.replace(from.as_str(), to.as_str());
745 }
746 result
747 }
748 pub fn len(&self) -> usize {
750 self.pairs.len()
751 }
752 pub fn is_empty(&self) -> bool {
754 self.pairs.is_empty()
755 }
756}
757#[allow(dead_code)]
759pub struct SparseVec<T: Default + Clone + PartialEq> {
760 entries: std::collections::HashMap<usize, T>,
761 default_: T,
762 logical_len: usize,
763}
764#[allow(dead_code)]
765impl<T: Default + Clone + PartialEq> SparseVec<T> {
766 pub fn new(len: usize) -> Self {
768 Self {
769 entries: std::collections::HashMap::new(),
770 default_: T::default(),
771 logical_len: len,
772 }
773 }
774 pub fn set(&mut self, idx: usize, val: T) {
776 if val == self.default_ {
777 self.entries.remove(&idx);
778 } else {
779 self.entries.insert(idx, val);
780 }
781 }
782 pub fn get(&self, idx: usize) -> &T {
784 self.entries.get(&idx).unwrap_or(&self.default_)
785 }
786 pub fn len(&self) -> usize {
788 self.logical_len
789 }
790 pub fn is_empty(&self) -> bool {
792 self.len() == 0
793 }
794 pub fn nnz(&self) -> usize {
796 self.entries.len()
797 }
798}
799#[allow(dead_code)]
801pub struct SmallMap<K: Ord + Clone, V: Clone> {
802 entries: Vec<(K, V)>,
803}
804#[allow(dead_code)]
805impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
806 pub fn new() -> Self {
808 Self {
809 entries: Vec::new(),
810 }
811 }
812 pub fn insert(&mut self, key: K, val: V) {
814 match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
815 Ok(i) => self.entries[i].1 = val,
816 Err(i) => self.entries.insert(i, (key, val)),
817 }
818 }
819 pub fn get(&self, key: &K) -> Option<&V> {
821 self.entries
822 .binary_search_by_key(&key, |(k, _)| k)
823 .ok()
824 .map(|i| &self.entries[i].1)
825 }
826 pub fn len(&self) -> usize {
828 self.entries.len()
829 }
830 pub fn is_empty(&self) -> bool {
832 self.entries.is_empty()
833 }
834 pub fn keys(&self) -> Vec<&K> {
836 self.entries.iter().map(|(k, _)| k).collect()
837 }
838 pub fn values(&self) -> Vec<&V> {
840 self.entries.iter().map(|(_, v)| v).collect()
841 }
842}
843#[allow(dead_code)]
845pub struct RewriteRuleSet {
846 rules: Vec<RewriteRule>,
847}
848#[allow(dead_code)]
849impl RewriteRuleSet {
850 pub fn new() -> Self {
852 Self { rules: Vec::new() }
853 }
854 pub fn add(&mut self, rule: RewriteRule) {
856 self.rules.push(rule);
857 }
858 pub fn len(&self) -> usize {
860 self.rules.len()
861 }
862 pub fn is_empty(&self) -> bool {
864 self.rules.is_empty()
865 }
866 pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
868 self.rules.iter().filter(|r| r.conditional).collect()
869 }
870 pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
872 self.rules.iter().filter(|r| !r.conditional).collect()
873 }
874 pub fn get(&self, name: &str) -> Option<&RewriteRule> {
876 self.rules.iter().find(|r| r.name == name)
877 }
878}
879#[allow(dead_code)]
881pub struct LabelSet {
882 labels: Vec<String>,
883}
884#[allow(dead_code)]
885impl LabelSet {
886 pub fn new() -> Self {
888 Self { labels: Vec::new() }
889 }
890 pub fn add(&mut self, label: impl Into<String>) {
892 let s = label.into();
893 if !self.labels.contains(&s) {
894 self.labels.push(s);
895 }
896 }
897 pub fn has(&self, label: &str) -> bool {
899 self.labels.iter().any(|l| l == label)
900 }
901 pub fn count(&self) -> usize {
903 self.labels.len()
904 }
905 pub fn all(&self) -> &[String] {
907 &self.labels
908 }
909}
910#[allow(dead_code)]
912#[allow(missing_docs)]
913pub enum DecisionNode {
914 Leaf(String),
916 Branch {
918 key: String,
919 val: String,
920 yes_branch: Box<DecisionNode>,
921 no_branch: Box<DecisionNode>,
922 },
923}
924#[allow(dead_code)]
925impl DecisionNode {
926 pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
928 match self {
929 DecisionNode::Leaf(action) => action.as_str(),
930 DecisionNode::Branch {
931 key,
932 val,
933 yes_branch,
934 no_branch,
935 } => {
936 let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
937 if actual == val.as_str() {
938 yes_branch.evaluate(ctx)
939 } else {
940 no_branch.evaluate(ctx)
941 }
942 }
943 }
944 }
945 pub fn depth(&self) -> usize {
947 match self {
948 DecisionNode::Leaf(_) => 0,
949 DecisionNode::Branch {
950 yes_branch,
951 no_branch,
952 ..
953 } => 1 + yes_branch.depth().max(no_branch.depth()),
954 }
955 }
956}
957#[allow(dead_code)]
959pub struct SimpleDag {
960 edges: Vec<Vec<usize>>,
962}
963#[allow(dead_code)]
964impl SimpleDag {
965 pub fn new(n: usize) -> Self {
967 Self {
968 edges: vec![Vec::new(); n],
969 }
970 }
971 pub fn add_edge(&mut self, from: usize, to: usize) {
973 if from < self.edges.len() {
974 self.edges[from].push(to);
975 }
976 }
977 pub fn successors(&self, node: usize) -> &[usize] {
979 self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
980 }
981 pub fn can_reach(&self, from: usize, to: usize) -> bool {
983 let mut visited = vec![false; self.edges.len()];
984 self.dfs(from, to, &mut visited)
985 }
986 fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
987 if cur == target {
988 return true;
989 }
990 if cur >= visited.len() || visited[cur] {
991 return false;
992 }
993 visited[cur] = true;
994 for &next in self.successors(cur) {
995 if self.dfs(next, target, visited) {
996 return true;
997 }
998 }
999 false
1000 }
1001 pub fn topological_sort(&self) -> Option<Vec<usize>> {
1003 let n = self.edges.len();
1004 let mut in_degree = vec![0usize; n];
1005 for succs in &self.edges {
1006 for &s in succs {
1007 if s < n {
1008 in_degree[s] += 1;
1009 }
1010 }
1011 }
1012 let mut queue: std::collections::VecDeque<usize> =
1013 (0..n).filter(|&i| in_degree[i] == 0).collect();
1014 let mut order = Vec::new();
1015 while let Some(node) = queue.pop_front() {
1016 order.push(node);
1017 for &s in self.successors(node) {
1018 if s < n {
1019 in_degree[s] -= 1;
1020 if in_degree[s] == 0 {
1021 queue.push_back(s);
1022 }
1023 }
1024 }
1025 }
1026 if order.len() == n {
1027 Some(order)
1028 } else {
1029 None
1030 }
1031 }
1032 pub fn num_nodes(&self) -> usize {
1034 self.edges.len()
1035 }
1036}
1037#[allow(dead_code)]
1041#[derive(Debug, Clone, Default)]
1042pub struct Substitution {
1043 pairs: Vec<(FVarId, Expr)>,
1044}
1045impl Substitution {
1046 #[allow(dead_code)]
1048 pub fn new() -> Self {
1049 Self { pairs: Vec::new() }
1050 }
1051 #[allow(dead_code)]
1053 pub fn insert(&mut self, fvar: FVarId, expr: Expr) {
1054 if let Some(existing) = self.pairs.iter_mut().find(|(f, _)| *f == fvar) {
1055 existing.1 = expr;
1056 } else {
1057 self.pairs.push((fvar, expr));
1058 }
1059 }
1060 #[allow(dead_code)]
1062 pub fn get(&self, fvar: FVarId) -> Option<&Expr> {
1063 self.pairs.iter().find(|(f, _)| *f == fvar).map(|(_, e)| e)
1064 }
1065 #[allow(dead_code)]
1067 pub fn len(&self) -> usize {
1068 self.pairs.len()
1069 }
1070 #[allow(dead_code)]
1072 pub fn is_empty(&self) -> bool {
1073 self.pairs.is_empty()
1074 }
1075 #[allow(dead_code)]
1079 pub fn apply(&self, expr: &Expr) -> Expr {
1080 if self.is_empty() {
1081 return expr.clone();
1082 }
1083 self.apply_inner(expr)
1084 }
1085 fn apply_inner(&self, expr: &Expr) -> Expr {
1086 match expr {
1087 Expr::FVar(id) => {
1088 if let Some(replacement) = self.get(*id) {
1089 replacement.clone()
1090 } else {
1091 expr.clone()
1092 }
1093 }
1094 Expr::App(f, a) => {
1095 Expr::App(Box::new(self.apply_inner(f)), Box::new(self.apply_inner(a)))
1096 }
1097 Expr::Lam(bi, name, ty, body) => Expr::Lam(
1098 *bi,
1099 name.clone(),
1100 Box::new(self.apply_inner(ty)),
1101 Box::new(self.apply_inner(body)),
1102 ),
1103 Expr::Pi(bi, name, ty, body) => Expr::Pi(
1104 *bi,
1105 name.clone(),
1106 Box::new(self.apply_inner(ty)),
1107 Box::new(self.apply_inner(body)),
1108 ),
1109 Expr::Let(name, ty, val, body) => Expr::Let(
1110 name.clone(),
1111 Box::new(self.apply_inner(ty)),
1112 Box::new(self.apply_inner(val)),
1113 Box::new(self.apply_inner(body)),
1114 ),
1115 Expr::Proj(name, idx, inner) => {
1116 Expr::Proj(name.clone(), *idx, Box::new(self.apply_inner(inner)))
1117 }
1118 _ => expr.clone(),
1119 }
1120 }
1121 #[allow(dead_code)]
1124 pub fn compose(&self, other: &Substitution) -> Substitution {
1125 let mut result = Substitution::new();
1126 for (fvar, expr) in &self.pairs {
1127 result.insert(*fvar, other.apply(expr));
1128 }
1129 for (fvar, expr) in &other.pairs {
1130 if self.get(*fvar).is_none() {
1131 result.insert(*fvar, expr.clone());
1132 }
1133 }
1134 result
1135 }
1136 #[allow(dead_code)]
1138 pub fn remove(&mut self, fvar: FVarId) {
1139 self.pairs.retain(|(f, _)| *f != fvar);
1140 }
1141 #[allow(dead_code)]
1143 pub fn restrict(&self, keep: &[FVarId]) -> Substitution {
1144 let pairs = self
1145 .pairs
1146 .iter()
1147 .filter(|(f, _)| keep.contains(f))
1148 .cloned()
1149 .collect();
1150 Substitution { pairs }
1151 }
1152}
1153#[allow(dead_code)]
1155pub struct Stopwatch {
1156 start: std::time::Instant,
1157 splits: Vec<f64>,
1158}
1159#[allow(dead_code)]
1160impl Stopwatch {
1161 pub fn start() -> Self {
1163 Self {
1164 start: std::time::Instant::now(),
1165 splits: Vec::new(),
1166 }
1167 }
1168 pub fn split(&mut self) {
1170 self.splits.push(self.elapsed_ms());
1171 }
1172 pub fn elapsed_ms(&self) -> f64 {
1174 self.start.elapsed().as_secs_f64() * 1000.0
1175 }
1176 pub fn splits(&self) -> &[f64] {
1178 &self.splits
1179 }
1180 pub fn num_splits(&self) -> usize {
1182 self.splits.len()
1183 }
1184}