1use super::functions::*;
6use crate::Node;
7use crate::{Expr, FVarId};
8use std::collections::HashMap;
9use std::rc::Rc;
10
11#[allow(dead_code)]
13pub struct TransformStat {
14 before: StatSummary,
15 after: StatSummary,
16}
17#[allow(dead_code)]
18impl TransformStat {
19 pub fn new() -> Self {
21 Self {
22 before: StatSummary::new(),
23 after: StatSummary::new(),
24 }
25 }
26 pub fn record_before(&mut self, v: f64) {
28 self.before.record(v);
29 }
30 pub fn record_after(&mut self, v: f64) {
32 self.after.record(v);
33 }
34 pub fn mean_ratio(&self) -> Option<f64> {
36 let b = self.before.mean()?;
37 let a = self.after.mean()?;
38 if b.abs() < f64::EPSILON {
39 return None;
40 }
41 Some(a / b)
42 }
43}
44#[allow(dead_code)]
46pub struct FocusStack<T> {
47 items: Vec<T>,
48}
49#[allow(dead_code)]
50impl<T> FocusStack<T> {
51 pub fn new() -> Self {
53 Self { items: Vec::new() }
54 }
55 pub fn focus(&mut self, item: T) {
57 self.items.push(item);
58 }
59 pub fn blur(&mut self) -> Option<T> {
61 self.items.pop()
62 }
63 pub fn current(&self) -> Option<&T> {
65 self.items.last()
66 }
67 pub fn depth(&self) -> usize {
69 self.items.len()
70 }
71 pub fn is_empty(&self) -> bool {
73 self.items.is_empty()
74 }
75}
76#[allow(dead_code)]
78pub struct PathBuf {
79 components: Vec<String>,
80}
81#[allow(dead_code)]
82impl PathBuf {
83 pub fn new() -> Self {
85 Self {
86 components: Vec::new(),
87 }
88 }
89 pub fn push(&mut self, comp: impl Into<String>) {
91 self.components.push(comp.into());
92 }
93 pub fn pop(&mut self) {
95 self.components.pop();
96 }
97 pub fn as_str(&self) -> String {
99 self.components.join("/")
100 }
101 pub fn depth(&self) -> usize {
103 self.components.len()
104 }
105 pub fn clear(&mut self) {
107 self.components.clear();
108 }
109}
110#[allow(dead_code)]
112pub struct TokenBucket {
113 capacity: u64,
114 tokens: u64,
115 refill_per_ms: u64,
116 last_refill: crate::wall_clock::Instant,
117}
118#[allow(dead_code)]
119impl TokenBucket {
120 pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
122 Self {
123 capacity,
124 tokens: capacity,
125 refill_per_ms,
126 last_refill: crate::wall_clock::Instant::now(),
127 }
128 }
129 pub fn try_consume(&mut self, n: u64) -> bool {
131 self.refill();
132 if self.tokens >= n {
133 self.tokens -= n;
134 true
135 } else {
136 false
137 }
138 }
139 fn refill(&mut self) {
140 let now = crate::wall_clock::Instant::now();
141 let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
142 if elapsed_ms > 0 {
143 let new_tokens = elapsed_ms * self.refill_per_ms;
144 self.tokens = (self.tokens + new_tokens).min(self.capacity);
145 self.last_refill = now;
146 }
147 }
148 pub fn available(&self) -> u64 {
150 self.tokens
151 }
152 pub fn capacity(&self) -> u64 {
154 self.capacity
155 }
156}
157#[allow(dead_code)]
159pub struct RawFnPtr {
160 ptr: usize,
162 arity: usize,
163 name: String,
164}
165#[allow(dead_code)]
166impl RawFnPtr {
167 pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
169 Self {
170 ptr,
171 arity,
172 name: name.into(),
173 }
174 }
175 pub fn arity(&self) -> usize {
177 self.arity
178 }
179 pub fn name(&self) -> &str {
181 &self.name
182 }
183 pub fn raw(&self) -> usize {
185 self.ptr
186 }
187}
188#[allow(dead_code)]
190pub enum Either2<A, B> {
191 First(A),
193 Second(B),
195}
196#[allow(dead_code)]
197impl<A, B> Either2<A, B> {
198 pub fn is_first(&self) -> bool {
200 matches!(self, Either2::First(_))
201 }
202 pub fn is_second(&self) -> bool {
204 matches!(self, Either2::Second(_))
205 }
206 pub fn first(self) -> Option<A> {
208 match self {
209 Either2::First(a) => Some(a),
210 _ => None,
211 }
212 }
213 pub fn second(self) -> Option<B> {
215 match self {
216 Either2::Second(b) => Some(b),
217 _ => None,
218 }
219 }
220 pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
222 match self {
223 Either2::First(a) => Either2::First(f(a)),
224 Either2::Second(b) => Either2::Second(b),
225 }
226 }
227}
228#[allow(dead_code)]
230pub struct SlidingSum {
231 window: Vec<f64>,
232 capacity: usize,
233 pos: usize,
234 sum: f64,
235 count: usize,
236}
237#[allow(dead_code)]
238impl SlidingSum {
239 pub fn new(capacity: usize) -> Self {
241 Self {
242 window: vec![0.0; capacity],
243 capacity,
244 pos: 0,
245 sum: 0.0,
246 count: 0,
247 }
248 }
249 pub fn push(&mut self, val: f64) {
251 let oldest = self.window[self.pos];
252 self.sum -= oldest;
253 self.sum += val;
254 self.window[self.pos] = val;
255 self.pos = (self.pos + 1) % self.capacity;
256 if self.count < self.capacity {
257 self.count += 1;
258 }
259 }
260 pub fn sum(&self) -> f64 {
262 self.sum
263 }
264 pub fn mean(&self) -> Option<f64> {
266 if self.count == 0 {
267 None
268 } else {
269 Some(self.sum / self.count as f64)
270 }
271 }
272 pub fn count(&self) -> usize {
274 self.count
275 }
276}
277#[allow(dead_code)]
279pub struct WriteOnce<T> {
280 value: std::cell::Cell<Option<T>>,
281}
282#[allow(dead_code)]
283impl<T: Copy> WriteOnce<T> {
284 pub fn new() -> Self {
286 Self {
287 value: std::cell::Cell::new(None),
288 }
289 }
290 pub fn write(&self, val: T) -> bool {
292 if self.value.get().is_some() {
293 return false;
294 }
295 self.value.set(Some(val));
296 true
297 }
298 pub fn read(&self) -> Option<T> {
300 self.value.get()
301 }
302 pub fn is_written(&self) -> bool {
304 self.value.get().is_some()
305 }
306}
307#[allow(dead_code)]
309pub struct StackCalc {
310 stack: Vec<i64>,
311}
312#[allow(dead_code)]
313impl StackCalc {
314 pub fn new() -> Self {
316 Self { stack: Vec::new() }
317 }
318 pub fn push(&mut self, n: i64) {
320 self.stack.push(n);
321 }
322 fn apply_binary(&mut self, op: impl FnOnce(i64, i64) -> i64) -> Option<i64> {
326 let (rest_len, a, b) = match self.stack[..] {
327 [ref rest @ .., a, b] => (rest.len(), a, b),
328 _ => return None,
329 };
330 let value = op(a, b);
331 self.stack.truncate(rest_len);
332 self.stack.push(value);
333 Some(value)
334 }
335 pub fn add(&mut self) -> Option<i64> {
339 self.apply_binary(|a, b| a + b)
340 }
341 pub fn sub(&mut self) -> Option<i64> {
345 self.apply_binary(|a, b| a - b)
346 }
347 pub fn mul(&mut self) -> Option<i64> {
351 self.apply_binary(|a, b| a * b)
352 }
353 pub fn peek(&self) -> Option<i64> {
355 self.stack.last().copied()
356 }
357 pub fn depth(&self) -> usize {
359 self.stack.len()
360 }
361}
362#[allow(dead_code)]
364pub struct StringPool {
365 free: Vec<String>,
366}
367#[allow(dead_code)]
368impl StringPool {
369 pub fn new() -> Self {
371 Self { free: Vec::new() }
372 }
373 pub fn take(&mut self) -> String {
375 self.free.pop().unwrap_or_default()
376 }
377 pub fn give(&mut self, mut s: String) {
379 s.clear();
380 self.free.push(s);
381 }
382 pub fn free_count(&self) -> usize {
384 self.free.len()
385 }
386}
387#[allow(dead_code)]
389pub struct NonEmptyVec<T> {
390 head: T,
391 tail: Vec<T>,
392}
393#[allow(dead_code)]
394impl<T> NonEmptyVec<T> {
395 pub fn singleton(val: T) -> Self {
397 Self {
398 head: val,
399 tail: Vec::new(),
400 }
401 }
402 pub fn push(&mut self, val: T) {
404 self.tail.push(val);
405 }
406 pub fn first(&self) -> &T {
408 &self.head
409 }
410 pub fn last(&self) -> &T {
412 self.tail.last().unwrap_or(&self.head)
413 }
414 pub fn len(&self) -> usize {
416 1 + self.tail.len()
417 }
418 pub fn is_empty(&self) -> bool {
420 self.len() == 0
421 }
422 pub fn to_vec(&self) -> Vec<&T> {
424 let mut v = vec![&self.head];
425 v.extend(self.tail.iter());
426 v
427 }
428}
429#[derive(Debug, Clone, Default, PartialEq, Eq)]
431pub struct SubstStats {
432 pub bvar_hits: usize,
434 pub bvar_misses: usize,
436 pub fvar_hits: usize,
438 pub nodes_visited: usize,
440}
441impl SubstStats {
442 pub fn merge(&mut self, other: &SubstStats) {
444 self.bvar_hits += other.bvar_hits;
445 self.bvar_misses += other.bvar_misses;
446 self.fvar_hits += other.fvar_hits;
447 self.nodes_visited += other.nodes_visited;
448 }
449 pub fn total_substs(&self) -> usize {
451 self.bvar_hits + self.fvar_hits
452 }
453}
454#[allow(dead_code)]
456pub struct ConfigNode {
457 key: String,
458 value: Option<String>,
459 children: Vec<ConfigNode>,
460}
461#[allow(dead_code)]
462impl ConfigNode {
463 pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
465 Self {
466 key: key.into(),
467 value: Some(value.into()),
468 children: Vec::new(),
469 }
470 }
471 pub fn section(key: impl Into<String>) -> Self {
473 Self {
474 key: key.into(),
475 value: None,
476 children: Vec::new(),
477 }
478 }
479 pub fn add_child(&mut self, child: ConfigNode) {
481 self.children.push(child);
482 }
483 pub fn key(&self) -> &str {
485 &self.key
486 }
487 pub fn value(&self) -> Option<&str> {
489 self.value.as_deref()
490 }
491 pub fn num_children(&self) -> usize {
493 self.children.len()
494 }
495 pub fn lookup(&self, path: &str) -> Option<&str> {
497 let mut parts = path.splitn(2, '.');
498 let head = parts.next()?;
499 let tail = parts.next();
500 if head != self.key {
501 return None;
502 }
503 match tail {
504 None => self.value.as_deref(),
505 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
506 }
507 }
508 fn lookup_relative(&self, path: &str) -> Option<&str> {
509 let mut parts = path.splitn(2, '.');
510 let head = parts.next()?;
511 let tail = parts.next();
512 if head != self.key {
513 return None;
514 }
515 match tail {
516 None => self.value.as_deref(),
517 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
518 }
519 }
520}
521#[allow(dead_code)]
523pub struct StatSummary {
524 count: u64,
525 sum: f64,
526 min: f64,
527 max: f64,
528}
529#[allow(dead_code)]
530impl StatSummary {
531 pub fn new() -> Self {
533 Self {
534 count: 0,
535 sum: 0.0,
536 min: f64::INFINITY,
537 max: f64::NEG_INFINITY,
538 }
539 }
540 pub fn record(&mut self, val: f64) {
542 self.count += 1;
543 self.sum += val;
544 if val < self.min {
545 self.min = val;
546 }
547 if val > self.max {
548 self.max = val;
549 }
550 }
551 pub fn mean(&self) -> Option<f64> {
553 if self.count == 0 {
554 None
555 } else {
556 Some(self.sum / self.count as f64)
557 }
558 }
559 pub fn min(&self) -> Option<f64> {
561 if self.count == 0 {
562 None
563 } else {
564 Some(self.min)
565 }
566 }
567 pub fn max(&self) -> Option<f64> {
569 if self.count == 0 {
570 None
571 } else {
572 Some(self.max)
573 }
574 }
575 pub fn count(&self) -> u64 {
577 self.count
578 }
579}
580#[allow(dead_code)]
582pub struct VersionedRecord<T: Clone> {
583 earlier: Vec<T>,
585 current: T,
587}
588#[allow(dead_code)]
589impl<T: Clone> VersionedRecord<T> {
590 pub fn new(initial: T) -> Self {
592 Self {
593 earlier: Vec::new(),
594 current: initial,
595 }
596 }
597 pub fn update(&mut self, val: T) {
599 let previous = std::mem::replace(&mut self.current, val);
600 self.earlier.push(previous);
601 }
602 pub fn current(&self) -> &T {
604 &self.current
605 }
606 pub fn at_version(&self, n: usize) -> Option<&T> {
608 match self.earlier.get(n) {
609 Some(value) => Some(value),
610 None if n == self.earlier.len() => Some(&self.current),
611 None => None,
612 }
613 }
614 pub fn version(&self) -> usize {
616 self.earlier.len()
617 }
618 pub fn has_history(&self) -> bool {
620 !self.earlier.is_empty()
621 }
622}
623#[allow(dead_code)]
625pub struct TransitiveClosure {
626 adj: Vec<Vec<usize>>,
627 n: usize,
628}
629#[allow(dead_code)]
630impl TransitiveClosure {
631 pub fn new(n: usize) -> Self {
633 Self {
634 adj: vec![Vec::new(); n],
635 n,
636 }
637 }
638 pub fn add_edge(&mut self, from: usize, to: usize) {
640 if from < self.n {
641 self.adj[from].push(to);
642 }
643 }
644 pub fn reachable_from(&self, start: usize) -> Vec<usize> {
646 let mut visited = vec![false; self.n];
647 let mut queue = std::collections::VecDeque::new();
648 queue.push_back(start);
649 while let Some(node) = queue.pop_front() {
650 if node >= self.n || visited[node] {
651 continue;
652 }
653 visited[node] = true;
654 for &next in &self.adj[node] {
655 queue.push_back(next);
656 }
657 }
658 (0..self.n).filter(|&i| visited[i]).collect()
659 }
660 pub fn can_reach(&self, from: usize, to: usize) -> bool {
662 self.reachable_from(from).contains(&to)
663 }
664}
665#[allow(dead_code)]
667#[allow(missing_docs)]
668pub struct RewriteRule {
669 pub name: String,
671 pub lhs: String,
673 pub rhs: String,
675 pub conditional: bool,
677}
678#[allow(dead_code)]
679impl RewriteRule {
680 pub fn unconditional(
682 name: impl Into<String>,
683 lhs: impl Into<String>,
684 rhs: impl Into<String>,
685 ) -> Self {
686 Self {
687 name: name.into(),
688 lhs: lhs.into(),
689 rhs: rhs.into(),
690 conditional: false,
691 }
692 }
693 pub fn conditional(
695 name: impl Into<String>,
696 lhs: impl Into<String>,
697 rhs: impl Into<String>,
698 ) -> Self {
699 Self {
700 name: name.into(),
701 lhs: lhs.into(),
702 rhs: rhs.into(),
703 conditional: true,
704 }
705 }
706 pub fn display(&self) -> String {
708 format!("{}: {} → {}", self.name, self.lhs, self.rhs)
709 }
710}
711#[allow(dead_code)]
713pub struct WindowIterator<'a, T> {
714 pub(super) data: &'a [T],
715 pub(super) pos: usize,
716 pub(super) window: usize,
717}
718#[allow(dead_code)]
719impl<'a, T> WindowIterator<'a, T> {
720 pub fn new(data: &'a [T], window: usize) -> Self {
722 Self {
723 data,
724 pos: 0,
725 window,
726 }
727 }
728}
729#[allow(dead_code)]
731pub struct FlatSubstitution {
732 pairs: Vec<(String, String)>,
733}
734#[allow(dead_code)]
735impl FlatSubstitution {
736 pub fn new() -> Self {
738 Self { pairs: Vec::new() }
739 }
740 pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
742 self.pairs.push((from.into(), to.into()));
743 }
744 pub fn apply(&self, s: &str) -> String {
746 let mut result = s.to_string();
747 for (from, to) in &self.pairs {
748 result = result.replace(from.as_str(), to.as_str());
749 }
750 result
751 }
752 pub fn len(&self) -> usize {
754 self.pairs.len()
755 }
756 pub fn is_empty(&self) -> bool {
758 self.pairs.is_empty()
759 }
760}
761#[allow(dead_code)]
763pub struct SparseVec<T: Default + Clone + PartialEq> {
764 entries: std::collections::HashMap<usize, T>,
765 default_: T,
766 logical_len: usize,
767}
768#[allow(dead_code)]
769impl<T: Default + Clone + PartialEq> SparseVec<T> {
770 pub fn new(len: usize) -> Self {
772 Self {
773 entries: std::collections::HashMap::new(),
774 default_: T::default(),
775 logical_len: len,
776 }
777 }
778 pub fn set(&mut self, idx: usize, val: T) {
780 if val == self.default_ {
781 self.entries.remove(&idx);
782 } else {
783 self.entries.insert(idx, val);
784 }
785 }
786 pub fn get(&self, idx: usize) -> &T {
788 self.entries.get(&idx).unwrap_or(&self.default_)
789 }
790 pub fn len(&self) -> usize {
792 self.logical_len
793 }
794 pub fn is_empty(&self) -> bool {
796 self.len() == 0
797 }
798 pub fn nnz(&self) -> usize {
800 self.entries.len()
801 }
802}
803#[allow(dead_code)]
805pub struct SmallMap<K: Ord + Clone, V: Clone> {
806 entries: Vec<(K, V)>,
807}
808#[allow(dead_code)]
809impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
810 pub fn new() -> Self {
812 Self {
813 entries: Vec::new(),
814 }
815 }
816 pub fn insert(&mut self, key: K, val: V) {
818 match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
819 Ok(i) => self.entries[i].1 = val,
820 Err(i) => self.entries.insert(i, (key, val)),
821 }
822 }
823 pub fn get(&self, key: &K) -> Option<&V> {
825 self.entries
826 .binary_search_by_key(&key, |(k, _)| k)
827 .ok()
828 .map(|i| &self.entries[i].1)
829 }
830 pub fn len(&self) -> usize {
832 self.entries.len()
833 }
834 pub fn is_empty(&self) -> bool {
836 self.entries.is_empty()
837 }
838 pub fn keys(&self) -> Vec<&K> {
840 self.entries.iter().map(|(k, _)| k).collect()
841 }
842 pub fn values(&self) -> Vec<&V> {
844 self.entries.iter().map(|(_, v)| v).collect()
845 }
846}
847#[allow(dead_code)]
849pub struct RewriteRuleSet {
850 rules: Vec<RewriteRule>,
851}
852#[allow(dead_code)]
853impl RewriteRuleSet {
854 pub fn new() -> Self {
856 Self { rules: Vec::new() }
857 }
858 pub fn add(&mut self, rule: RewriteRule) {
860 self.rules.push(rule);
861 }
862 pub fn len(&self) -> usize {
864 self.rules.len()
865 }
866 pub fn is_empty(&self) -> bool {
868 self.rules.is_empty()
869 }
870 pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
872 self.rules.iter().filter(|r| r.conditional).collect()
873 }
874 pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
876 self.rules.iter().filter(|r| !r.conditional).collect()
877 }
878 pub fn get(&self, name: &str) -> Option<&RewriteRule> {
880 self.rules.iter().find(|r| r.name == name)
881 }
882}
883#[allow(dead_code)]
885pub struct LabelSet {
886 labels: Vec<String>,
887}
888#[allow(dead_code)]
889impl LabelSet {
890 pub fn new() -> Self {
892 Self { labels: Vec::new() }
893 }
894 pub fn add(&mut self, label: impl Into<String>) {
896 let s = label.into();
897 if !self.labels.contains(&s) {
898 self.labels.push(s);
899 }
900 }
901 pub fn has(&self, label: &str) -> bool {
903 self.labels.iter().any(|l| l == label)
904 }
905 pub fn count(&self) -> usize {
907 self.labels.len()
908 }
909 pub fn all(&self) -> &[String] {
911 &self.labels
912 }
913}
914#[allow(dead_code)]
916#[allow(missing_docs)]
917pub enum DecisionNode {
918 Leaf(String),
920 Branch {
922 key: String,
923 val: String,
924 yes_branch: Box<DecisionNode>,
925 no_branch: Box<DecisionNode>,
926 },
927}
928#[allow(dead_code)]
929impl DecisionNode {
930 pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
932 match self {
933 DecisionNode::Leaf(action) => action.as_str(),
934 DecisionNode::Branch {
935 key,
936 val,
937 yes_branch,
938 no_branch,
939 } => {
940 let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
941 if actual == val.as_str() {
942 yes_branch.evaluate(ctx)
943 } else {
944 no_branch.evaluate(ctx)
945 }
946 }
947 }
948 }
949 pub fn depth(&self) -> usize {
951 match self {
952 DecisionNode::Leaf(_) => 0,
953 DecisionNode::Branch {
954 yes_branch,
955 no_branch,
956 ..
957 } => 1 + yes_branch.depth().max(no_branch.depth()),
958 }
959 }
960}
961#[allow(dead_code)]
963pub struct SimpleDag {
964 edges: Vec<Vec<usize>>,
966}
967#[allow(dead_code)]
968impl SimpleDag {
969 pub fn new(n: usize) -> Self {
971 Self {
972 edges: vec![Vec::new(); n],
973 }
974 }
975 pub fn add_edge(&mut self, from: usize, to: usize) {
977 if from < self.edges.len() {
978 self.edges[from].push(to);
979 }
980 }
981 pub fn successors(&self, node: usize) -> &[usize] {
983 self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
984 }
985 pub fn can_reach(&self, from: usize, to: usize) -> bool {
987 let mut visited = vec![false; self.edges.len()];
988 self.dfs(from, to, &mut visited)
989 }
990 fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
991 if cur == target {
992 return true;
993 }
994 if cur >= visited.len() || visited[cur] {
995 return false;
996 }
997 visited[cur] = true;
998 for &next in self.successors(cur) {
999 if self.dfs(next, target, visited) {
1000 return true;
1001 }
1002 }
1003 false
1004 }
1005 pub fn topological_sort(&self) -> Option<Vec<usize>> {
1007 let n = self.edges.len();
1008 let mut in_degree = vec![0usize; n];
1009 for succs in &self.edges {
1010 for &s in succs {
1011 if s < n {
1012 in_degree[s] += 1;
1013 }
1014 }
1015 }
1016 let mut queue: std::collections::VecDeque<usize> =
1017 (0..n).filter(|&i| in_degree[i] == 0).collect();
1018 let mut order = Vec::new();
1019 while let Some(node) = queue.pop_front() {
1020 order.push(node);
1021 for &s in self.successors(node) {
1022 if s < n {
1023 in_degree[s] -= 1;
1024 if in_degree[s] == 0 {
1025 queue.push_back(s);
1026 }
1027 }
1028 }
1029 }
1030 if order.len() == n {
1031 Some(order)
1032 } else {
1033 None
1034 }
1035 }
1036 pub fn num_nodes(&self) -> usize {
1038 self.edges.len()
1039 }
1040}
1041#[allow(dead_code)]
1045#[derive(Debug, Clone, Default)]
1046pub struct Substitution {
1047 pairs: Vec<(FVarId, Expr)>,
1048}
1049impl Substitution {
1050 #[allow(dead_code)]
1052 pub fn new() -> Self {
1053 Self { pairs: Vec::new() }
1054 }
1055 #[allow(dead_code)]
1057 pub fn insert(&mut self, fvar: FVarId, expr: Expr) {
1058 if let Some(existing) = self.pairs.iter_mut().find(|(f, _)| *f == fvar) {
1059 existing.1 = expr;
1060 } else {
1061 self.pairs.push((fvar, expr));
1062 }
1063 }
1064 #[allow(dead_code)]
1066 pub fn get(&self, fvar: FVarId) -> Option<&Expr> {
1067 self.pairs.iter().find(|(f, _)| *f == fvar).map(|(_, e)| e)
1068 }
1069 #[allow(dead_code)]
1071 pub fn len(&self) -> usize {
1072 self.pairs.len()
1073 }
1074 #[allow(dead_code)]
1076 pub fn is_empty(&self) -> bool {
1077 self.pairs.is_empty()
1078 }
1079 #[allow(dead_code)]
1083 pub fn apply(&self, expr: &Expr) -> Expr {
1084 if self.is_empty() {
1085 return expr.clone();
1086 }
1087 self.apply_inner(expr)
1088 }
1089 fn apply_inner(&self, expr: &Expr) -> Expr {
1090 match expr {
1091 Expr::FVar(id) => {
1092 if let Some(replacement) = self.get(*id) {
1093 replacement.clone()
1094 } else {
1095 expr.clone()
1096 }
1097 }
1098 Expr::App(f, a) => Expr::App(
1099 Node::new(self.apply_inner(f)),
1100 Node::new(self.apply_inner(a)),
1101 ),
1102 Expr::Lam(bi, name, ty, body) => Expr::Lam(
1103 *bi,
1104 name.clone(),
1105 Node::new(self.apply_inner(ty)),
1106 Node::new(self.apply_inner(body)),
1107 ),
1108 Expr::Pi(bi, name, ty, body) => Expr::Pi(
1109 *bi,
1110 name.clone(),
1111 Node::new(self.apply_inner(ty)),
1112 Node::new(self.apply_inner(body)),
1113 ),
1114 Expr::Let(name, ty, val, body) => Expr::Let(
1115 name.clone(),
1116 Node::new(self.apply_inner(ty)),
1117 Node::new(self.apply_inner(val)),
1118 Node::new(self.apply_inner(body)),
1119 ),
1120 Expr::Proj(name, idx, inner) => {
1121 Expr::Proj(name.clone(), *idx, Node::new(self.apply_inner(inner)))
1122 }
1123 _ => expr.clone(),
1124 }
1125 }
1126 #[allow(dead_code)]
1129 pub fn compose(&self, other: &Substitution) -> Substitution {
1130 let mut result = Substitution::new();
1131 for (fvar, expr) in &self.pairs {
1132 result.insert(*fvar, other.apply(expr));
1133 }
1134 for (fvar, expr) in &other.pairs {
1135 if self.get(*fvar).is_none() {
1136 result.insert(*fvar, expr.clone());
1137 }
1138 }
1139 result
1140 }
1141 #[allow(dead_code)]
1143 pub fn remove(&mut self, fvar: FVarId) {
1144 self.pairs.retain(|(f, _)| *f != fvar);
1145 }
1146 #[allow(dead_code)]
1148 pub fn restrict(&self, keep: &[FVarId]) -> Substitution {
1149 let pairs = self
1150 .pairs
1151 .iter()
1152 .filter(|(f, _)| keep.contains(f))
1153 .cloned()
1154 .collect();
1155 Substitution { pairs }
1156 }
1157}
1158#[allow(dead_code)]
1160pub struct Stopwatch {
1161 start: crate::wall_clock::Instant,
1162 splits: Vec<f64>,
1163}
1164#[allow(dead_code)]
1165impl Stopwatch {
1166 pub fn start() -> Self {
1168 Self {
1169 start: crate::wall_clock::Instant::now(),
1170 splits: Vec::new(),
1171 }
1172 }
1173 pub fn split(&mut self) {
1175 self.splits.push(self.elapsed_ms());
1176 }
1177 pub fn elapsed_ms(&self) -> f64 {
1179 self.start.elapsed().as_secs_f64() * 1000.0
1180 }
1181 pub fn splits(&self) -> &[f64] {
1183 &self.splits
1184 }
1185 pub fn num_splits(&self) -> usize {
1187 self.splits.len()
1188 }
1189}