1use crate::reduce::TransparencyMode;
6use crate::{Environment, Expr, Reducer};
7
8use std::collections::HashMap;
9
10use super::functions::coercion_head_matches;
11
12#[allow(dead_code)]
14pub struct SimpleDag {
15 edges: Vec<Vec<usize>>,
17}
18#[allow(dead_code)]
19impl SimpleDag {
20 pub fn new(n: usize) -> Self {
22 Self {
23 edges: vec![Vec::new(); n],
24 }
25 }
26 pub fn add_edge(&mut self, from: usize, to: usize) {
28 if from < self.edges.len() {
29 self.edges[from].push(to);
30 }
31 }
32 pub fn successors(&self, node: usize) -> &[usize] {
34 self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
35 }
36 pub fn can_reach(&self, from: usize, to: usize) -> bool {
38 let mut visited = vec![false; self.edges.len()];
39 self.dfs(from, to, &mut visited)
40 }
41 fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
42 if cur == target {
43 return true;
44 }
45 if cur >= visited.len() || visited[cur] {
46 return false;
47 }
48 visited[cur] = true;
49 for &next in self.successors(cur) {
50 if self.dfs(next, target, visited) {
51 return true;
52 }
53 }
54 false
55 }
56 pub fn topological_sort(&self) -> Option<Vec<usize>> {
58 let n = self.edges.len();
59 let mut in_degree = vec![0usize; n];
60 for succs in &self.edges {
61 for &s in succs {
62 if s < n {
63 in_degree[s] += 1;
64 }
65 }
66 }
67 let mut queue: std::collections::VecDeque<usize> =
68 (0..n).filter(|&i| in_degree[i] == 0).collect();
69 let mut order = Vec::new();
70 while let Some(node) = queue.pop_front() {
71 order.push(node);
72 for &s in self.successors(node) {
73 if s < n {
74 in_degree[s] -= 1;
75 if in_degree[s] == 0 {
76 queue.push_back(s);
77 }
78 }
79 }
80 }
81 if order.len() == n {
82 Some(order)
83 } else {
84 None
85 }
86 }
87 pub fn num_nodes(&self) -> usize {
89 self.edges.len()
90 }
91}
92#[allow(dead_code)]
94pub struct TokenBucket {
95 capacity: u64,
96 tokens: u64,
97 refill_per_ms: u64,
98 last_refill: std::time::Instant,
99}
100#[allow(dead_code)]
101impl TokenBucket {
102 pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
104 Self {
105 capacity,
106 tokens: capacity,
107 refill_per_ms,
108 last_refill: std::time::Instant::now(),
109 }
110 }
111 pub fn try_consume(&mut self, n: u64) -> bool {
113 self.refill();
114 if self.tokens >= n {
115 self.tokens -= n;
116 true
117 } else {
118 false
119 }
120 }
121 fn refill(&mut self) {
122 let now = std::time::Instant::now();
123 let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
124 if elapsed_ms > 0 {
125 let new_tokens = elapsed_ms * self.refill_per_ms;
126 self.tokens = (self.tokens + new_tokens).min(self.capacity);
127 self.last_refill = now;
128 }
129 }
130 pub fn available(&self) -> u64 {
132 self.tokens
133 }
134 pub fn capacity(&self) -> u64 {
136 self.capacity
137 }
138}
139#[allow(dead_code)]
141pub struct WriteOnce<T> {
142 value: std::cell::Cell<Option<T>>,
143}
144#[allow(dead_code)]
145impl<T: Copy> WriteOnce<T> {
146 pub fn new() -> Self {
148 Self {
149 value: std::cell::Cell::new(None),
150 }
151 }
152 pub fn write(&self, val: T) -> bool {
154 if self.value.get().is_some() {
155 return false;
156 }
157 self.value.set(Some(val));
158 true
159 }
160 pub fn read(&self) -> Option<T> {
162 self.value.get()
163 }
164 pub fn is_written(&self) -> bool {
166 self.value.get().is_some()
167 }
168}
169#[allow(dead_code)]
171pub struct ConfigNode {
172 key: String,
173 value: Option<String>,
174 children: Vec<ConfigNode>,
175}
176#[allow(dead_code)]
177impl ConfigNode {
178 pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
180 Self {
181 key: key.into(),
182 value: Some(value.into()),
183 children: Vec::new(),
184 }
185 }
186 pub fn section(key: impl Into<String>) -> Self {
188 Self {
189 key: key.into(),
190 value: None,
191 children: Vec::new(),
192 }
193 }
194 pub fn add_child(&mut self, child: ConfigNode) {
196 self.children.push(child);
197 }
198 pub fn key(&self) -> &str {
200 &self.key
201 }
202 pub fn value(&self) -> Option<&str> {
204 self.value.as_deref()
205 }
206 pub fn num_children(&self) -> usize {
208 self.children.len()
209 }
210 pub fn lookup(&self, path: &str) -> Option<&str> {
212 let mut parts = path.splitn(2, '.');
213 let head = parts.next()?;
214 let tail = parts.next();
215 if head != self.key {
216 return None;
217 }
218 match tail {
219 None => self.value.as_deref(),
220 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
221 }
222 }
223 fn lookup_relative(&self, path: &str) -> Option<&str> {
224 let mut parts = path.splitn(2, '.');
225 let head = parts.next()?;
226 let tail = parts.next();
227 if head != self.key {
228 return None;
229 }
230 match tail {
231 None => self.value.as_deref(),
232 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
233 }
234 }
235}
236#[derive(Debug, Clone)]
238pub enum ConvResult {
239 Equal,
241 NotEqual,
243 Timeout {
246 steps: usize,
248 },
249 Error(String),
251}
252impl ConvResult {
253 pub fn is_equal(&self) -> bool {
255 matches!(self, ConvResult::Equal)
256 }
257 pub fn is_definitive(&self) -> bool {
259 matches!(self, ConvResult::Equal | ConvResult::NotEqual)
260 }
261}
262#[allow(dead_code)]
264pub struct VersionedRecord<T: Clone> {
265 history: Vec<T>,
266}
267#[allow(dead_code)]
268impl<T: Clone> VersionedRecord<T> {
269 pub fn new(initial: T) -> Self {
271 Self {
272 history: vec![initial],
273 }
274 }
275 pub fn update(&mut self, val: T) {
277 self.history.push(val);
278 }
279 pub fn current(&self) -> &T {
281 self.history
282 .last()
283 .expect("VersionedRecord history is always non-empty after construction")
284 }
285 pub fn at_version(&self, n: usize) -> Option<&T> {
287 self.history.get(n)
288 }
289 pub fn version(&self) -> usize {
291 self.history.len() - 1
292 }
293 pub fn has_history(&self) -> bool {
295 self.history.len() > 1
296 }
297}
298#[allow(dead_code)]
300#[allow(missing_docs)]
301pub enum DecisionNode {
302 Leaf(String),
304 Branch {
306 key: String,
307 val: String,
308 yes_branch: Box<DecisionNode>,
309 no_branch: Box<DecisionNode>,
310 },
311}
312#[allow(dead_code)]
313impl DecisionNode {
314 pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
316 match self {
317 DecisionNode::Leaf(action) => action.as_str(),
318 DecisionNode::Branch {
319 key,
320 val,
321 yes_branch,
322 no_branch,
323 } => {
324 let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
325 if actual == val.as_str() {
326 yes_branch.evaluate(ctx)
327 } else {
328 no_branch.evaluate(ctx)
329 }
330 }
331 }
332 }
333 pub fn depth(&self) -> usize {
335 match self {
336 DecisionNode::Leaf(_) => 0,
337 DecisionNode::Branch {
338 yes_branch,
339 no_branch,
340 ..
341 } => 1 + yes_branch.depth().max(no_branch.depth()),
342 }
343 }
344}
345pub struct ConversionChecker {
349 reducer: Reducer,
351 max_steps: usize,
353 transparency: TransparencyMode,
355}
356impl ConversionChecker {
357 pub fn new() -> Self {
359 Self {
360 reducer: Reducer::new(),
361 max_steps: 10000,
362 transparency: TransparencyMode::Default,
363 }
364 }
365 pub fn with_transparency(mode: TransparencyMode) -> Self {
367 let mut checker = Self::new();
368 checker.set_transparency(mode);
369 checker
370 }
371 pub fn set_transparency(&mut self, mode: TransparencyMode) {
373 self.transparency = mode;
374 self.reducer.set_transparency(mode);
375 }
376 pub fn transparency(&self) -> TransparencyMode {
378 self.transparency
379 }
380 pub fn is_convertible(&mut self, e1: &Expr, e2: &Expr) -> bool {
382 self.is_convertible_impl(e1, e2, 0)
383 }
384 pub fn is_convertible_in_env(&mut self, e1: &Expr, e2: &Expr, env: &Environment) -> bool {
386 self.is_convertible_env_impl(e1, e2, env, 0)
387 }
388 fn is_convertible_impl(&mut self, e1: &Expr, e2: &Expr, depth: usize) -> bool {
390 if depth > self.max_steps {
391 return false;
392 }
393 if e1 == e2 {
394 return true;
395 }
396 let whnf1 = self.reducer.whnf(e1);
397 let whnf2 = self.reducer.whnf(e2);
398 self.structural_eq(&whnf1, &whnf2, depth)
399 }
400 fn is_convertible_env_impl(
402 &mut self,
403 e1: &Expr,
404 e2: &Expr,
405 env: &Environment,
406 depth: usize,
407 ) -> bool {
408 if depth > self.max_steps {
409 return false;
410 }
411 if e1 == e2 {
412 return true;
413 }
414 let whnf1 = self.reducer.whnf_env(e1, env);
415 let whnf2 = self.reducer.whnf_env(e2, env);
416 self.structural_eq_env(&whnf1, &whnf2, env, depth)
417 }
418 fn structural_eq(&mut self, e1: &Expr, e2: &Expr, depth: usize) -> bool {
420 if e1 == e2 {
421 return true;
422 }
423 match (e1, e2) {
424 (Expr::BVar(i1), Expr::BVar(i2)) => i1 == i2,
425 (Expr::FVar(f1), Expr::FVar(f2)) => f1 == f2,
426 (Expr::Const(n1, ls1), Expr::Const(n2, ls2)) => {
427 n1 == n2
428 && ls1.len() == ls2.len()
429 && ls1.iter().zip(ls2.iter()).all(|(a, b)| a == b)
430 }
431 (Expr::Sort(l1), Expr::Sort(l2)) => crate::level::is_equivalent(l1, l2),
432 (Expr::Lit(l1), Expr::Lit(l2)) => l1 == l2,
433 (Expr::App(f1, a1), Expr::App(f2, a2)) => {
434 self.is_convertible_impl(f1, f2, depth + 1)
435 && self.is_convertible_impl(a1, a2, depth + 1)
436 }
437 (Expr::Lam(_, _, ty1, body1), Expr::Lam(_, _, ty2, body2)) => {
438 self.is_convertible_impl(ty1, ty2, depth + 1)
439 && self.is_convertible_impl(body1, body2, depth + 1)
440 }
441 (Expr::Pi(_, _, ty1, body1), Expr::Pi(_, _, ty2, body2)) => {
442 self.is_convertible_impl(ty1, ty2, depth + 1)
443 && self.is_convertible_impl(body1, body2, depth + 1)
444 }
445 (Expr::Let(_, ty1, val1, body1), Expr::Let(_, ty2, val2, body2)) => {
446 self.is_convertible_impl(ty1, ty2, depth + 1)
447 && self.is_convertible_impl(val1, val2, depth + 1)
448 && self.is_convertible_impl(body1, body2, depth + 1)
449 }
450 (Expr::Proj(n1, i1, e1), Expr::Proj(n2, i2, e2)) => {
451 n1 == n2 && i1 == i2 && self.is_convertible_impl(e1, e2, depth + 1)
452 }
453 _ => false,
454 }
455 }
456 fn structural_eq_env(&mut self, e1: &Expr, e2: &Expr, env: &Environment, depth: usize) -> bool {
458 if e1 == e2 {
459 return true;
460 }
461 match (e1, e2) {
462 (Expr::BVar(i1), Expr::BVar(i2)) => i1 == i2,
463 (Expr::FVar(f1), Expr::FVar(f2)) => f1 == f2,
464 (Expr::Const(n1, ls1), Expr::Const(n2, ls2)) => {
465 n1 == n2
466 && ls1.len() == ls2.len()
467 && ls1.iter().zip(ls2.iter()).all(|(a, b)| a == b)
468 }
469 (Expr::Sort(l1), Expr::Sort(l2)) => crate::level::is_equivalent(l1, l2),
470 (Expr::Lit(l1), Expr::Lit(l2)) => l1 == l2,
471 (Expr::App(f1, a1), Expr::App(f2, a2)) => {
472 self.is_convertible_env_impl(f1, f2, env, depth + 1)
473 && self.is_convertible_env_impl(a1, a2, env, depth + 1)
474 }
475 (Expr::Lam(_, _, ty1, body1), Expr::Lam(_, _, ty2, body2)) => {
476 self.is_convertible_env_impl(ty1, ty2, env, depth + 1)
477 && self.is_convertible_env_impl(body1, body2, env, depth + 1)
478 }
479 (Expr::Pi(_, _, ty1, body1), Expr::Pi(_, _, ty2, body2)) => {
480 self.is_convertible_env_impl(ty1, ty2, env, depth + 1)
481 && self.is_convertible_env_impl(body1, body2, env, depth + 1)
482 }
483 (Expr::Let(_, ty1, val1, body1), Expr::Let(_, ty2, val2, body2)) => {
484 self.is_convertible_env_impl(ty1, ty2, env, depth + 1)
485 && self.is_convertible_env_impl(val1, val2, env, depth + 1)
486 && self.is_convertible_env_impl(body1, body2, env, depth + 1)
487 }
488 (Expr::Proj(n1, i1, e1), Expr::Proj(n2, i2, e2)) => {
489 n1 == n2 && i1 == i2 && self.is_convertible_env_impl(e1, e2, env, depth + 1)
490 }
491 _ => false,
492 }
493 }
494 pub fn set_max_steps(&mut self, max: usize) {
496 self.max_steps = max;
497 }
498 pub fn max_steps(&self) -> usize {
500 self.max_steps
501 }
502}
503#[allow(dead_code)]
505pub struct SmallMap<K: Ord + Clone, V: Clone> {
506 entries: Vec<(K, V)>,
507}
508#[allow(dead_code)]
509impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
510 pub fn new() -> Self {
512 Self {
513 entries: Vec::new(),
514 }
515 }
516 pub fn insert(&mut self, key: K, val: V) {
518 match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
519 Ok(i) => self.entries[i].1 = val,
520 Err(i) => self.entries.insert(i, (key, val)),
521 }
522 }
523 pub fn get(&self, key: &K) -> Option<&V> {
525 self.entries
526 .binary_search_by_key(&key, |(k, _)| k)
527 .ok()
528 .map(|i| &self.entries[i].1)
529 }
530 pub fn len(&self) -> usize {
532 self.entries.len()
533 }
534 pub fn is_empty(&self) -> bool {
536 self.entries.is_empty()
537 }
538 pub fn keys(&self) -> Vec<&K> {
540 self.entries.iter().map(|(k, _)| k).collect()
541 }
542 pub fn values(&self) -> Vec<&V> {
544 self.entries.iter().map(|(_, v)| v).collect()
545 }
546}
547#[allow(dead_code)]
549pub struct RewriteRuleSet {
550 rules: Vec<RewriteRule>,
551}
552#[allow(dead_code)]
553impl RewriteRuleSet {
554 pub fn new() -> Self {
556 Self { rules: Vec::new() }
557 }
558 pub fn add(&mut self, rule: RewriteRule) {
560 self.rules.push(rule);
561 }
562 pub fn len(&self) -> usize {
564 self.rules.len()
565 }
566 pub fn is_empty(&self) -> bool {
568 self.rules.is_empty()
569 }
570 pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
572 self.rules.iter().filter(|r| r.conditional).collect()
573 }
574 pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
576 self.rules.iter().filter(|r| !r.conditional).collect()
577 }
578 pub fn get(&self, name: &str) -> Option<&RewriteRule> {
580 self.rules.iter().find(|r| r.name == name)
581 }
582}
583#[derive(Debug, Clone)]
585#[allow(dead_code)]
586pub struct Coercion {
587 pub name: crate::Name,
589 pub source: crate::Expr,
591 pub target: crate::Expr,
593 pub priority: i32,
595}
596#[allow(dead_code)]
598pub struct NonEmptyVec<T> {
599 head: T,
600 tail: Vec<T>,
601}
602#[allow(dead_code)]
603impl<T> NonEmptyVec<T> {
604 pub fn singleton(val: T) -> Self {
606 Self {
607 head: val,
608 tail: Vec::new(),
609 }
610 }
611 pub fn push(&mut self, val: T) {
613 self.tail.push(val);
614 }
615 pub fn first(&self) -> &T {
617 &self.head
618 }
619 pub fn last(&self) -> &T {
621 self.tail.last().unwrap_or(&self.head)
622 }
623 pub fn len(&self) -> usize {
625 1 + self.tail.len()
626 }
627 pub fn is_empty(&self) -> bool {
629 self.len() == 0
630 }
631 pub fn to_vec(&self) -> Vec<&T> {
633 let mut v = vec![&self.head];
634 v.extend(self.tail.iter());
635 v
636 }
637}
638#[allow(dead_code)]
640pub struct MinHeap<T: Ord> {
641 data: Vec<T>,
642}
643#[allow(dead_code)]
644impl<T: Ord> MinHeap<T> {
645 pub fn new() -> Self {
647 Self { data: Vec::new() }
648 }
649 pub fn push(&mut self, val: T) {
651 self.data.push(val);
652 self.sift_up(self.data.len() - 1);
653 }
654 pub fn pop(&mut self) -> Option<T> {
656 if self.data.is_empty() {
657 return None;
658 }
659 let n = self.data.len();
660 self.data.swap(0, n - 1);
661 let min = self.data.pop();
662 if !self.data.is_empty() {
663 self.sift_down(0);
664 }
665 min
666 }
667 pub fn peek(&self) -> Option<&T> {
669 self.data.first()
670 }
671 pub fn len(&self) -> usize {
673 self.data.len()
674 }
675 pub fn is_empty(&self) -> bool {
677 self.data.is_empty()
678 }
679 fn sift_up(&mut self, mut i: usize) {
680 while i > 0 {
681 let parent = (i - 1) / 2;
682 if self.data[i] < self.data[parent] {
683 self.data.swap(i, parent);
684 i = parent;
685 } else {
686 break;
687 }
688 }
689 }
690 fn sift_down(&mut self, mut i: usize) {
691 let n = self.data.len();
692 loop {
693 let left = 2 * i + 1;
694 let right = 2 * i + 2;
695 let mut smallest = i;
696 if left < n && self.data[left] < self.data[smallest] {
697 smallest = left;
698 }
699 if right < n && self.data[right] < self.data[smallest] {
700 smallest = right;
701 }
702 if smallest == i {
703 break;
704 }
705 self.data.swap(i, smallest);
706 i = smallest;
707 }
708 }
709}
710#[allow(dead_code)]
712pub struct SlidingSum {
713 window: Vec<f64>,
714 capacity: usize,
715 pos: usize,
716 sum: f64,
717 count: usize,
718}
719#[allow(dead_code)]
720impl SlidingSum {
721 pub fn new(capacity: usize) -> Self {
723 Self {
724 window: vec![0.0; capacity],
725 capacity,
726 pos: 0,
727 sum: 0.0,
728 count: 0,
729 }
730 }
731 pub fn push(&mut self, val: f64) {
733 let oldest = self.window[self.pos];
734 self.sum -= oldest;
735 self.sum += val;
736 self.window[self.pos] = val;
737 self.pos = (self.pos + 1) % self.capacity;
738 if self.count < self.capacity {
739 self.count += 1;
740 }
741 }
742 pub fn sum(&self) -> f64 {
744 self.sum
745 }
746 pub fn mean(&self) -> Option<f64> {
748 if self.count == 0 {
749 None
750 } else {
751 Some(self.sum / self.count as f64)
752 }
753 }
754 pub fn count(&self) -> usize {
756 self.count
757 }
758}
759#[allow(dead_code)]
761pub struct StackCalc {
762 stack: Vec<i64>,
763}
764#[allow(dead_code)]
765impl StackCalc {
766 pub fn new() -> Self {
768 Self { stack: Vec::new() }
769 }
770 pub fn push(&mut self, n: i64) {
772 self.stack.push(n);
773 }
774 pub fn add(&mut self) {
776 let b = self
777 .stack
778 .pop()
779 .expect("stack must have at least two values for add");
780 let a = self
781 .stack
782 .pop()
783 .expect("stack must have at least two values for add");
784 self.stack.push(a + b);
785 }
786 pub fn sub(&mut self) {
788 let b = self
789 .stack
790 .pop()
791 .expect("stack must have at least two values for sub");
792 let a = self
793 .stack
794 .pop()
795 .expect("stack must have at least two values for sub");
796 self.stack.push(a - b);
797 }
798 pub fn mul(&mut self) {
800 let b = self
801 .stack
802 .pop()
803 .expect("stack must have at least two values for mul");
804 let a = self
805 .stack
806 .pop()
807 .expect("stack must have at least two values for mul");
808 self.stack.push(a * b);
809 }
810 pub fn peek(&self) -> Option<i64> {
812 self.stack.last().copied()
813 }
814 pub fn depth(&self) -> usize {
816 self.stack.len()
817 }
818}
819#[allow(dead_code)]
821pub struct FlatSubstitution {
822 pairs: Vec<(String, String)>,
823}
824#[allow(dead_code)]
825impl FlatSubstitution {
826 pub fn new() -> Self {
828 Self { pairs: Vec::new() }
829 }
830 pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
832 self.pairs.push((from.into(), to.into()));
833 }
834 pub fn apply(&self, s: &str) -> String {
836 let mut result = s.to_string();
837 for (from, to) in &self.pairs {
838 result = result.replace(from.as_str(), to.as_str());
839 }
840 result
841 }
842 pub fn len(&self) -> usize {
844 self.pairs.len()
845 }
846 pub fn is_empty(&self) -> bool {
848 self.pairs.is_empty()
849 }
850}
851#[allow(dead_code)]
853pub struct StatSummary {
854 count: u64,
855 sum: f64,
856 min: f64,
857 max: f64,
858}
859#[allow(dead_code)]
860impl StatSummary {
861 pub fn new() -> Self {
863 Self {
864 count: 0,
865 sum: 0.0,
866 min: f64::INFINITY,
867 max: f64::NEG_INFINITY,
868 }
869 }
870 pub fn record(&mut self, val: f64) {
872 self.count += 1;
873 self.sum += val;
874 if val < self.min {
875 self.min = val;
876 }
877 if val > self.max {
878 self.max = val;
879 }
880 }
881 pub fn mean(&self) -> Option<f64> {
883 if self.count == 0 {
884 None
885 } else {
886 Some(self.sum / self.count as f64)
887 }
888 }
889 pub fn min(&self) -> Option<f64> {
891 if self.count == 0 {
892 None
893 } else {
894 Some(self.min)
895 }
896 }
897 pub fn max(&self) -> Option<f64> {
899 if self.count == 0 {
900 None
901 } else {
902 Some(self.max)
903 }
904 }
905 pub fn count(&self) -> u64 {
907 self.count
908 }
909}
910#[allow(dead_code)]
912pub struct TransitiveClosure {
913 adj: Vec<Vec<usize>>,
914 n: usize,
915}
916#[allow(dead_code)]
917impl TransitiveClosure {
918 pub fn new(n: usize) -> Self {
920 Self {
921 adj: vec![Vec::new(); n],
922 n,
923 }
924 }
925 pub fn add_edge(&mut self, from: usize, to: usize) {
927 if from < self.n {
928 self.adj[from].push(to);
929 }
930 }
931 pub fn reachable_from(&self, start: usize) -> Vec<usize> {
933 let mut visited = vec![false; self.n];
934 let mut queue = std::collections::VecDeque::new();
935 queue.push_back(start);
936 while let Some(node) = queue.pop_front() {
937 if node >= self.n || visited[node] {
938 continue;
939 }
940 visited[node] = true;
941 for &next in &self.adj[node] {
942 queue.push_back(next);
943 }
944 }
945 (0..self.n).filter(|&i| visited[i]).collect()
946 }
947 pub fn can_reach(&self, from: usize, to: usize) -> bool {
949 self.reachable_from(from).contains(&to)
950 }
951}
952#[allow(dead_code)]
954pub struct PathBuf {
955 components: Vec<String>,
956}
957#[allow(dead_code)]
958impl PathBuf {
959 pub fn new() -> Self {
961 Self {
962 components: Vec::new(),
963 }
964 }
965 pub fn push(&mut self, comp: impl Into<String>) {
967 self.components.push(comp.into());
968 }
969 pub fn pop(&mut self) {
971 self.components.pop();
972 }
973 pub fn as_str(&self) -> String {
975 self.components.join("/")
976 }
977 pub fn depth(&self) -> usize {
979 self.components.len()
980 }
981 pub fn clear(&mut self) {
983 self.components.clear();
984 }
985}
986#[allow(dead_code)]
988pub struct SparseVec<T: Default + Clone + PartialEq> {
989 entries: std::collections::HashMap<usize, T>,
990 default_: T,
991 logical_len: usize,
992}
993#[allow(dead_code)]
994impl<T: Default + Clone + PartialEq> SparseVec<T> {
995 pub fn new(len: usize) -> Self {
997 Self {
998 entries: std::collections::HashMap::new(),
999 default_: T::default(),
1000 logical_len: len,
1001 }
1002 }
1003 pub fn set(&mut self, idx: usize, val: T) {
1005 if val == self.default_ {
1006 self.entries.remove(&idx);
1007 } else {
1008 self.entries.insert(idx, val);
1009 }
1010 }
1011 pub fn get(&self, idx: usize) -> &T {
1013 self.entries.get(&idx).unwrap_or(&self.default_)
1014 }
1015 pub fn len(&self) -> usize {
1017 self.logical_len
1018 }
1019 pub fn is_empty(&self) -> bool {
1021 self.len() == 0
1022 }
1023 pub fn nnz(&self) -> usize {
1025 self.entries.len()
1026 }
1027}
1028#[allow(dead_code)]
1030pub struct WindowIterator<'a, T> {
1031 pub(super) data: &'a [T],
1032 pub(super) pos: usize,
1033 pub(super) window: usize,
1034}
1035#[allow(dead_code)]
1036impl<'a, T> WindowIterator<'a, T> {
1037 pub fn new(data: &'a [T], window: usize) -> Self {
1039 Self {
1040 data,
1041 pos: 0,
1042 window,
1043 }
1044 }
1045}
1046#[allow(dead_code)]
1048pub struct StringPool {
1049 free: Vec<String>,
1050}
1051#[allow(dead_code)]
1052impl StringPool {
1053 pub fn new() -> Self {
1055 Self { free: Vec::new() }
1056 }
1057 pub fn take(&mut self) -> String {
1059 self.free.pop().unwrap_or_default()
1060 }
1061 pub fn give(&mut self, mut s: String) {
1063 s.clear();
1064 self.free.push(s);
1065 }
1066 pub fn free_count(&self) -> usize {
1068 self.free.len()
1069 }
1070}
1071#[allow(dead_code)]
1073pub struct BitSet64 {
1074 bits: u64,
1075}
1076#[allow(dead_code)]
1077impl BitSet64 {
1078 pub const fn new() -> Self {
1080 Self { bits: 0 }
1081 }
1082 pub fn insert(&mut self, i: u32) {
1084 if i < 64 {
1085 self.bits |= 1u64 << i;
1086 }
1087 }
1088 pub fn remove(&mut self, i: u32) {
1090 if i < 64 {
1091 self.bits &= !(1u64 << i);
1092 }
1093 }
1094 pub fn contains(&self, i: u32) -> bool {
1096 i < 64 && (self.bits >> i) & 1 != 0
1097 }
1098 pub fn len(&self) -> u32 {
1100 self.bits.count_ones()
1101 }
1102 pub fn is_empty(&self) -> bool {
1104 self.bits == 0
1105 }
1106 pub fn union(self, other: BitSet64) -> BitSet64 {
1108 BitSet64 {
1109 bits: self.bits | other.bits,
1110 }
1111 }
1112 pub fn intersect(self, other: BitSet64) -> BitSet64 {
1114 BitSet64 {
1115 bits: self.bits & other.bits,
1116 }
1117 }
1118}
1119#[allow(dead_code)]
1121pub struct PrefixCounter {
1122 children: std::collections::HashMap<char, PrefixCounter>,
1123 count: usize,
1124}
1125#[allow(dead_code)]
1126impl PrefixCounter {
1127 pub fn new() -> Self {
1129 Self {
1130 children: std::collections::HashMap::new(),
1131 count: 0,
1132 }
1133 }
1134 pub fn record(&mut self, s: &str) {
1136 self.count += 1;
1137 let mut node = self;
1138 for c in s.chars() {
1139 node = node.children.entry(c).or_default();
1140 node.count += 1;
1141 }
1142 }
1143 pub fn count_with_prefix(&self, prefix: &str) -> usize {
1145 let mut node = self;
1146 for c in prefix.chars() {
1147 match node.children.get(&c) {
1148 Some(n) => node = n,
1149 None => return 0,
1150 }
1151 }
1152 node.count
1153 }
1154}
1155#[allow(dead_code)]
1157#[allow(missing_docs)]
1158pub struct RewriteRule {
1159 pub name: String,
1161 pub lhs: String,
1163 pub rhs: String,
1165 pub conditional: bool,
1167}
1168#[allow(dead_code)]
1169impl RewriteRule {
1170 pub fn unconditional(
1172 name: impl Into<String>,
1173 lhs: impl Into<String>,
1174 rhs: impl Into<String>,
1175 ) -> Self {
1176 Self {
1177 name: name.into(),
1178 lhs: lhs.into(),
1179 rhs: rhs.into(),
1180 conditional: false,
1181 }
1182 }
1183 pub fn conditional(
1185 name: impl Into<String>,
1186 lhs: impl Into<String>,
1187 rhs: impl Into<String>,
1188 ) -> Self {
1189 Self {
1190 name: name.into(),
1191 lhs: lhs.into(),
1192 rhs: rhs.into(),
1193 conditional: true,
1194 }
1195 }
1196 pub fn display(&self) -> String {
1198 format!("{}: {} → {}", self.name, self.lhs, self.rhs)
1199 }
1200}
1201#[derive(Default)]
1203#[allow(dead_code)]
1204pub struct CoercionTable {
1205 coercions: Vec<Coercion>,
1206}
1207impl CoercionTable {
1208 pub fn new() -> Self {
1210 Self {
1211 coercions: Vec::new(),
1212 }
1213 }
1214 pub fn register(&mut self, coercion: Coercion) {
1216 let pos = self
1217 .coercions
1218 .partition_point(|c| c.priority >= coercion.priority);
1219 self.coercions.insert(pos, coercion);
1220 }
1221 pub fn find(&self, source_head: &crate::Name) -> Vec<&Coercion> {
1223 self.coercions
1224 .iter()
1225 .filter(|c| coercion_head_matches(&c.source, source_head))
1226 .collect()
1227 }
1228 pub fn len(&self) -> usize {
1230 self.coercions.len()
1231 }
1232 pub fn is_empty(&self) -> bool {
1234 self.coercions.is_empty()
1235 }
1236 pub fn clear(&mut self) {
1238 self.coercions.clear();
1239 }
1240}
1241#[allow(dead_code)]
1243pub enum Either2<A, B> {
1244 First(A),
1246 Second(B),
1248}
1249#[allow(dead_code)]
1250impl<A, B> Either2<A, B> {
1251 pub fn is_first(&self) -> bool {
1253 matches!(self, Either2::First(_))
1254 }
1255 pub fn is_second(&self) -> bool {
1257 matches!(self, Either2::Second(_))
1258 }
1259 pub fn first(self) -> Option<A> {
1261 match self {
1262 Either2::First(a) => Some(a),
1263 _ => None,
1264 }
1265 }
1266 pub fn second(self) -> Option<B> {
1268 match self {
1269 Either2::Second(b) => Some(b),
1270 _ => None,
1271 }
1272 }
1273 pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
1275 match self {
1276 Either2::First(a) => Either2::First(f(a)),
1277 Either2::Second(b) => Either2::Second(b),
1278 }
1279 }
1280}
1281#[allow(dead_code)]
1283pub struct FocusStack<T> {
1284 items: Vec<T>,
1285}
1286#[allow(dead_code)]
1287impl<T> FocusStack<T> {
1288 pub fn new() -> Self {
1290 Self { items: Vec::new() }
1291 }
1292 pub fn focus(&mut self, item: T) {
1294 self.items.push(item);
1295 }
1296 pub fn blur(&mut self) -> Option<T> {
1298 self.items.pop()
1299 }
1300 pub fn current(&self) -> Option<&T> {
1302 self.items.last()
1303 }
1304 pub fn depth(&self) -> usize {
1306 self.items.len()
1307 }
1308 pub fn is_empty(&self) -> bool {
1310 self.items.is_empty()
1311 }
1312}
1313#[allow(dead_code)]
1315pub struct RawFnPtr {
1316 ptr: usize,
1318 arity: usize,
1319 name: String,
1320}
1321#[allow(dead_code)]
1322impl RawFnPtr {
1323 pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
1325 Self {
1326 ptr,
1327 arity,
1328 name: name.into(),
1329 }
1330 }
1331 pub fn arity(&self) -> usize {
1333 self.arity
1334 }
1335 pub fn name(&self) -> &str {
1337 &self.name
1338 }
1339 pub fn raw(&self) -> usize {
1341 self.ptr
1342 }
1343}
1344#[allow(dead_code)]
1346pub struct Stopwatch {
1347 start: std::time::Instant,
1348 splits: Vec<f64>,
1349}
1350#[allow(dead_code)]
1351impl Stopwatch {
1352 pub fn start() -> Self {
1354 Self {
1355 start: std::time::Instant::now(),
1356 splits: Vec::new(),
1357 }
1358 }
1359 pub fn split(&mut self) {
1361 self.splits.push(self.elapsed_ms());
1362 }
1363 pub fn elapsed_ms(&self) -> f64 {
1365 self.start.elapsed().as_secs_f64() * 1000.0
1366 }
1367 pub fn splits(&self) -> &[f64] {
1369 &self.splits
1370 }
1371 pub fn num_splits(&self) -> usize {
1373 self.splits.len()
1374 }
1375}
1376#[allow(dead_code)]
1378pub struct Fixture {
1379 data: std::collections::HashMap<String, String>,
1380}
1381#[allow(dead_code)]
1382impl Fixture {
1383 pub fn new() -> Self {
1385 Self {
1386 data: std::collections::HashMap::new(),
1387 }
1388 }
1389 pub fn set(&mut self, key: impl Into<String>, val: impl Into<String>) {
1391 self.data.insert(key.into(), val.into());
1392 }
1393 pub fn get(&self, key: &str) -> Option<&str> {
1395 self.data.get(key).map(|s| s.as_str())
1396 }
1397 pub fn len(&self) -> usize {
1399 self.data.len()
1400 }
1401 pub fn is_empty(&self) -> bool {
1403 self.len() == 0
1404 }
1405}
1406#[allow(dead_code)]
1408pub struct TransformStat {
1409 before: StatSummary,
1410 after: StatSummary,
1411}
1412#[allow(dead_code)]
1413impl TransformStat {
1414 pub fn new() -> Self {
1416 Self {
1417 before: StatSummary::new(),
1418 after: StatSummary::new(),
1419 }
1420 }
1421 pub fn record_before(&mut self, v: f64) {
1423 self.before.record(v);
1424 }
1425 pub fn record_after(&mut self, v: f64) {
1427 self.after.record(v);
1428 }
1429 pub fn mean_ratio(&self) -> Option<f64> {
1431 let b = self.before.mean()?;
1432 let a = self.after.mean()?;
1433 if b.abs() < f64::EPSILON {
1434 return None;
1435 }
1436 Some(a / b)
1437 }
1438}
1439#[allow(dead_code)]
1441pub struct BucketCounter<const N: usize> {
1442 buckets: [u64; N],
1443}
1444#[allow(dead_code)]
1445impl<const N: usize> BucketCounter<N> {
1446 pub const fn new() -> Self {
1448 Self { buckets: [0u64; N] }
1449 }
1450 pub fn inc(&mut self, i: usize) {
1452 if i < N {
1453 self.buckets[i] += 1;
1454 }
1455 }
1456 pub fn get(&self, i: usize) -> u64 {
1458 if i < N {
1459 self.buckets[i]
1460 } else {
1461 0
1462 }
1463 }
1464 pub fn total(&self) -> u64 {
1466 self.buckets.iter().sum()
1467 }
1468 pub fn argmax(&self) -> usize {
1470 self.buckets
1471 .iter()
1472 .enumerate()
1473 .max_by_key(|(_, &v)| v)
1474 .map(|(i, _)| i)
1475 .unwrap_or(0)
1476 }
1477}
1478#[allow(dead_code)]
1480pub struct LabelSet {
1481 labels: Vec<String>,
1482}
1483#[allow(dead_code)]
1484impl LabelSet {
1485 pub fn new() -> Self {
1487 Self { labels: Vec::new() }
1488 }
1489 pub fn add(&mut self, label: impl Into<String>) {
1491 let s = label.into();
1492 if !self.labels.contains(&s) {
1493 self.labels.push(s);
1494 }
1495 }
1496 pub fn has(&self, label: &str) -> bool {
1498 self.labels.iter().any(|l| l == label)
1499 }
1500 pub fn count(&self) -> usize {
1502 self.labels.len()
1503 }
1504 pub fn all(&self) -> &[String] {
1506 &self.labels
1507 }
1508}