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: crate::wall_clock::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: crate::wall_clock::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 = crate::wall_clock::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 earlier: Vec<T>,
267 current: T,
269}
270#[allow(dead_code)]
271impl<T: Clone> VersionedRecord<T> {
272 pub fn new(initial: T) -> Self {
274 Self {
275 earlier: Vec::new(),
276 current: initial,
277 }
278 }
279 pub fn update(&mut self, val: T) {
281 let previous = std::mem::replace(&mut self.current, val);
282 self.earlier.push(previous);
283 }
284 pub fn current(&self) -> &T {
286 &self.current
287 }
288 pub fn at_version(&self, n: usize) -> Option<&T> {
290 match self.earlier.get(n) {
291 Some(value) => Some(value),
292 None if n == self.earlier.len() => Some(&self.current),
293 None => None,
294 }
295 }
296 pub fn version(&self) -> usize {
298 self.earlier.len()
299 }
300 pub fn has_history(&self) -> bool {
302 !self.earlier.is_empty()
303 }
304}
305#[allow(dead_code)]
307#[allow(missing_docs)]
308pub enum DecisionNode {
309 Leaf(String),
311 Branch {
313 key: String,
314 val: String,
315 yes_branch: Box<DecisionNode>,
316 no_branch: Box<DecisionNode>,
317 },
318}
319#[allow(dead_code)]
320impl DecisionNode {
321 pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
323 match self {
324 DecisionNode::Leaf(action) => action.as_str(),
325 DecisionNode::Branch {
326 key,
327 val,
328 yes_branch,
329 no_branch,
330 } => {
331 let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
332 if actual == val.as_str() {
333 yes_branch.evaluate(ctx)
334 } else {
335 no_branch.evaluate(ctx)
336 }
337 }
338 }
339 }
340 pub fn depth(&self) -> usize {
342 match self {
343 DecisionNode::Leaf(_) => 0,
344 DecisionNode::Branch {
345 yes_branch,
346 no_branch,
347 ..
348 } => 1 + yes_branch.depth().max(no_branch.depth()),
349 }
350 }
351}
352pub struct ConversionChecker {
356 reducer: Reducer,
358 max_steps: usize,
360 transparency: TransparencyMode,
362}
363impl ConversionChecker {
364 pub fn new() -> Self {
366 Self {
367 reducer: Reducer::new(),
368 max_steps: 10000,
369 transparency: TransparencyMode::Default,
370 }
371 }
372 pub fn with_transparency(mode: TransparencyMode) -> Self {
374 let mut checker = Self::new();
375 checker.set_transparency(mode);
376 checker
377 }
378 pub fn set_transparency(&mut self, mode: TransparencyMode) {
380 self.transparency = mode;
381 self.reducer.set_transparency(mode);
382 }
383 pub fn transparency(&self) -> TransparencyMode {
385 self.transparency
386 }
387 pub fn is_convertible(&mut self, e1: &Expr, e2: &Expr) -> bool {
389 self.is_convertible_impl(e1, e2, 0)
390 }
391 pub fn is_convertible_in_env(&mut self, e1: &Expr, e2: &Expr, env: &Environment) -> bool {
393 self.is_convertible_env_impl(e1, e2, env, 0)
394 }
395 fn is_convertible_impl(&mut self, e1: &Expr, e2: &Expr, depth: usize) -> bool {
397 if depth > self.max_steps {
398 return false;
399 }
400 if e1 == e2 {
401 return true;
402 }
403 let whnf1 = self.reducer.whnf(e1);
404 let whnf2 = self.reducer.whnf(e2);
405 self.structural_eq(&whnf1, &whnf2, depth)
406 }
407 fn is_convertible_env_impl(
409 &mut self,
410 e1: &Expr,
411 e2: &Expr,
412 env: &Environment,
413 depth: usize,
414 ) -> bool {
415 if depth > self.max_steps {
416 return false;
417 }
418 if e1 == e2 {
419 return true;
420 }
421 let whnf1 = self.reducer.whnf_env(e1, env);
422 let whnf2 = self.reducer.whnf_env(e2, env);
423 self.structural_eq_env(&whnf1, &whnf2, env, depth)
424 }
425 fn structural_eq(&mut self, e1: &Expr, e2: &Expr, depth: usize) -> bool {
427 if e1 == e2 {
428 return true;
429 }
430 match (e1, e2) {
431 (Expr::BVar(i1), Expr::BVar(i2)) => i1 == i2,
432 (Expr::FVar(f1), Expr::FVar(f2)) => f1 == f2,
433 (Expr::Const(n1, ls1), Expr::Const(n2, ls2)) => {
434 n1 == n2
435 && ls1.len() == ls2.len()
436 && ls1.iter().zip(ls2.iter()).all(|(a, b)| a == b)
437 }
438 (Expr::Sort(l1), Expr::Sort(l2)) => crate::level::is_equivalent(l1, l2),
439 (Expr::Lit(l1), Expr::Lit(l2)) => l1 == l2,
440 (Expr::App(f1, a1), Expr::App(f2, a2)) => {
441 self.is_convertible_impl(f1, f2, depth + 1)
442 && self.is_convertible_impl(a1, a2, depth + 1)
443 }
444 (Expr::Lam(_, _, ty1, body1), Expr::Lam(_, _, ty2, body2)) => {
445 self.is_convertible_impl(ty1, ty2, depth + 1)
446 && self.is_convertible_impl(body1, body2, depth + 1)
447 }
448 (Expr::Pi(_, _, ty1, body1), Expr::Pi(_, _, ty2, body2)) => {
449 self.is_convertible_impl(ty1, ty2, depth + 1)
450 && self.is_convertible_impl(body1, body2, depth + 1)
451 }
452 (Expr::Let(_, ty1, val1, body1), Expr::Let(_, ty2, val2, body2)) => {
453 self.is_convertible_impl(ty1, ty2, depth + 1)
454 && self.is_convertible_impl(val1, val2, depth + 1)
455 && self.is_convertible_impl(body1, body2, depth + 1)
456 }
457 (Expr::Proj(n1, i1, e1), Expr::Proj(n2, i2, e2)) => {
458 n1 == n2 && i1 == i2 && self.is_convertible_impl(e1, e2, depth + 1)
459 }
460 _ => false,
461 }
462 }
463 fn structural_eq_env(&mut self, e1: &Expr, e2: &Expr, env: &Environment, depth: usize) -> bool {
465 if e1 == e2 {
466 return true;
467 }
468 match (e1, e2) {
469 (Expr::BVar(i1), Expr::BVar(i2)) => i1 == i2,
470 (Expr::FVar(f1), Expr::FVar(f2)) => f1 == f2,
471 (Expr::Const(n1, ls1), Expr::Const(n2, ls2)) => {
472 n1 == n2
473 && ls1.len() == ls2.len()
474 && ls1.iter().zip(ls2.iter()).all(|(a, b)| a == b)
475 }
476 (Expr::Sort(l1), Expr::Sort(l2)) => crate::level::is_equivalent(l1, l2),
477 (Expr::Lit(l1), Expr::Lit(l2)) => l1 == l2,
478 (Expr::App(f1, a1), Expr::App(f2, a2)) => {
479 self.is_convertible_env_impl(f1, f2, env, depth + 1)
480 && self.is_convertible_env_impl(a1, a2, env, depth + 1)
481 }
482 (Expr::Lam(_, _, ty1, body1), Expr::Lam(_, _, ty2, body2)) => {
483 self.is_convertible_env_impl(ty1, ty2, env, depth + 1)
484 && self.is_convertible_env_impl(body1, body2, env, depth + 1)
485 }
486 (Expr::Pi(_, _, ty1, body1), Expr::Pi(_, _, ty2, body2)) => {
487 self.is_convertible_env_impl(ty1, ty2, env, depth + 1)
488 && self.is_convertible_env_impl(body1, body2, env, depth + 1)
489 }
490 (Expr::Let(_, ty1, val1, body1), Expr::Let(_, ty2, val2, body2)) => {
491 self.is_convertible_env_impl(ty1, ty2, env, depth + 1)
492 && self.is_convertible_env_impl(val1, val2, env, depth + 1)
493 && self.is_convertible_env_impl(body1, body2, env, depth + 1)
494 }
495 (Expr::Proj(n1, i1, e1), Expr::Proj(n2, i2, e2)) => {
496 n1 == n2 && i1 == i2 && self.is_convertible_env_impl(e1, e2, env, depth + 1)
497 }
498 _ => false,
499 }
500 }
501 pub fn set_max_steps(&mut self, max: usize) {
503 self.max_steps = max;
504 }
505 pub fn max_steps(&self) -> usize {
507 self.max_steps
508 }
509}
510#[allow(dead_code)]
512pub struct SmallMap<K: Ord + Clone, V: Clone> {
513 entries: Vec<(K, V)>,
514}
515#[allow(dead_code)]
516impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
517 pub fn new() -> Self {
519 Self {
520 entries: Vec::new(),
521 }
522 }
523 pub fn insert(&mut self, key: K, val: V) {
525 match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
526 Ok(i) => self.entries[i].1 = val,
527 Err(i) => self.entries.insert(i, (key, val)),
528 }
529 }
530 pub fn get(&self, key: &K) -> Option<&V> {
532 self.entries
533 .binary_search_by_key(&key, |(k, _)| k)
534 .ok()
535 .map(|i| &self.entries[i].1)
536 }
537 pub fn len(&self) -> usize {
539 self.entries.len()
540 }
541 pub fn is_empty(&self) -> bool {
543 self.entries.is_empty()
544 }
545 pub fn keys(&self) -> Vec<&K> {
547 self.entries.iter().map(|(k, _)| k).collect()
548 }
549 pub fn values(&self) -> Vec<&V> {
551 self.entries.iter().map(|(_, v)| v).collect()
552 }
553}
554#[allow(dead_code)]
556pub struct RewriteRuleSet {
557 rules: Vec<RewriteRule>,
558}
559#[allow(dead_code)]
560impl RewriteRuleSet {
561 pub fn new() -> Self {
563 Self { rules: Vec::new() }
564 }
565 pub fn add(&mut self, rule: RewriteRule) {
567 self.rules.push(rule);
568 }
569 pub fn len(&self) -> usize {
571 self.rules.len()
572 }
573 pub fn is_empty(&self) -> bool {
575 self.rules.is_empty()
576 }
577 pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
579 self.rules.iter().filter(|r| r.conditional).collect()
580 }
581 pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
583 self.rules.iter().filter(|r| !r.conditional).collect()
584 }
585 pub fn get(&self, name: &str) -> Option<&RewriteRule> {
587 self.rules.iter().find(|r| r.name == name)
588 }
589}
590#[derive(Debug, Clone)]
592#[allow(dead_code)]
593pub struct Coercion {
594 pub name: crate::Name,
596 pub source: crate::Expr,
598 pub target: crate::Expr,
600 pub priority: i32,
602}
603#[allow(dead_code)]
605pub struct NonEmptyVec<T> {
606 head: T,
607 tail: Vec<T>,
608}
609#[allow(dead_code)]
610impl<T> NonEmptyVec<T> {
611 pub fn singleton(val: T) -> Self {
613 Self {
614 head: val,
615 tail: Vec::new(),
616 }
617 }
618 pub fn push(&mut self, val: T) {
620 self.tail.push(val);
621 }
622 pub fn first(&self) -> &T {
624 &self.head
625 }
626 pub fn last(&self) -> &T {
628 self.tail.last().unwrap_or(&self.head)
629 }
630 pub fn len(&self) -> usize {
632 1 + self.tail.len()
633 }
634 pub fn is_empty(&self) -> bool {
636 self.len() == 0
637 }
638 pub fn to_vec(&self) -> Vec<&T> {
640 let mut v = vec![&self.head];
641 v.extend(self.tail.iter());
642 v
643 }
644}
645#[allow(dead_code)]
647pub struct MinHeap<T: Ord> {
648 data: Vec<T>,
649}
650#[allow(dead_code)]
651impl<T: Ord> MinHeap<T> {
652 pub fn new() -> Self {
654 Self { data: Vec::new() }
655 }
656 pub fn push(&mut self, val: T) {
658 self.data.push(val);
659 self.sift_up(self.data.len() - 1);
660 }
661 pub fn pop(&mut self) -> Option<T> {
663 if self.data.is_empty() {
664 return None;
665 }
666 let n = self.data.len();
667 self.data.swap(0, n - 1);
668 let min = self.data.pop();
669 if !self.data.is_empty() {
670 self.sift_down(0);
671 }
672 min
673 }
674 pub fn peek(&self) -> Option<&T> {
676 self.data.first()
677 }
678 pub fn len(&self) -> usize {
680 self.data.len()
681 }
682 pub fn is_empty(&self) -> bool {
684 self.data.is_empty()
685 }
686 fn sift_up(&mut self, mut i: usize) {
687 while i > 0 {
688 let parent = (i - 1) / 2;
689 if self.data[i] < self.data[parent] {
690 self.data.swap(i, parent);
691 i = parent;
692 } else {
693 break;
694 }
695 }
696 }
697 fn sift_down(&mut self, mut i: usize) {
698 let n = self.data.len();
699 loop {
700 let left = 2 * i + 1;
701 let right = 2 * i + 2;
702 let mut smallest = i;
703 if left < n && self.data[left] < self.data[smallest] {
704 smallest = left;
705 }
706 if right < n && self.data[right] < self.data[smallest] {
707 smallest = right;
708 }
709 if smallest == i {
710 break;
711 }
712 self.data.swap(i, smallest);
713 i = smallest;
714 }
715 }
716}
717#[allow(dead_code)]
719pub struct SlidingSum {
720 window: Vec<f64>,
721 capacity: usize,
722 pos: usize,
723 sum: f64,
724 count: usize,
725}
726#[allow(dead_code)]
727impl SlidingSum {
728 pub fn new(capacity: usize) -> Self {
730 Self {
731 window: vec![0.0; capacity],
732 capacity,
733 pos: 0,
734 sum: 0.0,
735 count: 0,
736 }
737 }
738 pub fn push(&mut self, val: f64) {
740 let oldest = self.window[self.pos];
741 self.sum -= oldest;
742 self.sum += val;
743 self.window[self.pos] = val;
744 self.pos = (self.pos + 1) % self.capacity;
745 if self.count < self.capacity {
746 self.count += 1;
747 }
748 }
749 pub fn sum(&self) -> f64 {
751 self.sum
752 }
753 pub fn mean(&self) -> Option<f64> {
755 if self.count == 0 {
756 None
757 } else {
758 Some(self.sum / self.count as f64)
759 }
760 }
761 pub fn count(&self) -> usize {
763 self.count
764 }
765}
766#[allow(dead_code)]
768pub struct StackCalc {
769 stack: Vec<i64>,
770}
771#[allow(dead_code)]
772impl StackCalc {
773 pub fn new() -> Self {
775 Self { stack: Vec::new() }
776 }
777 pub fn push(&mut self, n: i64) {
779 self.stack.push(n);
780 }
781 fn apply_binary(&mut self, op: impl FnOnce(i64, i64) -> i64) -> Option<i64> {
785 let (rest_len, a, b) = match self.stack[..] {
786 [ref rest @ .., a, b] => (rest.len(), a, b),
787 _ => return None,
788 };
789 let value = op(a, b);
790 self.stack.truncate(rest_len);
791 self.stack.push(value);
792 Some(value)
793 }
794 pub fn add(&mut self) -> Option<i64> {
798 self.apply_binary(|a, b| a + b)
799 }
800 pub fn sub(&mut self) -> Option<i64> {
804 self.apply_binary(|a, b| a - b)
805 }
806 pub fn mul(&mut self) -> Option<i64> {
810 self.apply_binary(|a, b| a * b)
811 }
812 pub fn peek(&self) -> Option<i64> {
814 self.stack.last().copied()
815 }
816 pub fn depth(&self) -> usize {
818 self.stack.len()
819 }
820}
821#[allow(dead_code)]
823pub struct FlatSubstitution {
824 pairs: Vec<(String, String)>,
825}
826#[allow(dead_code)]
827impl FlatSubstitution {
828 pub fn new() -> Self {
830 Self { pairs: Vec::new() }
831 }
832 pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
834 self.pairs.push((from.into(), to.into()));
835 }
836 pub fn apply(&self, s: &str) -> String {
838 let mut result = s.to_string();
839 for (from, to) in &self.pairs {
840 result = result.replace(from.as_str(), to.as_str());
841 }
842 result
843 }
844 pub fn len(&self) -> usize {
846 self.pairs.len()
847 }
848 pub fn is_empty(&self) -> bool {
850 self.pairs.is_empty()
851 }
852}
853#[allow(dead_code)]
855pub struct StatSummary {
856 count: u64,
857 sum: f64,
858 min: f64,
859 max: f64,
860}
861#[allow(dead_code)]
862impl StatSummary {
863 pub fn new() -> Self {
865 Self {
866 count: 0,
867 sum: 0.0,
868 min: f64::INFINITY,
869 max: f64::NEG_INFINITY,
870 }
871 }
872 pub fn record(&mut self, val: f64) {
874 self.count += 1;
875 self.sum += val;
876 if val < self.min {
877 self.min = val;
878 }
879 if val > self.max {
880 self.max = val;
881 }
882 }
883 pub fn mean(&self) -> Option<f64> {
885 if self.count == 0 {
886 None
887 } else {
888 Some(self.sum / self.count as f64)
889 }
890 }
891 pub fn min(&self) -> Option<f64> {
893 if self.count == 0 {
894 None
895 } else {
896 Some(self.min)
897 }
898 }
899 pub fn max(&self) -> Option<f64> {
901 if self.count == 0 {
902 None
903 } else {
904 Some(self.max)
905 }
906 }
907 pub fn count(&self) -> u64 {
909 self.count
910 }
911}
912#[allow(dead_code)]
914pub struct TransitiveClosure {
915 adj: Vec<Vec<usize>>,
916 n: usize,
917}
918#[allow(dead_code)]
919impl TransitiveClosure {
920 pub fn new(n: usize) -> Self {
922 Self {
923 adj: vec![Vec::new(); n],
924 n,
925 }
926 }
927 pub fn add_edge(&mut self, from: usize, to: usize) {
929 if from < self.n {
930 self.adj[from].push(to);
931 }
932 }
933 pub fn reachable_from(&self, start: usize) -> Vec<usize> {
935 let mut visited = vec![false; self.n];
936 let mut queue = std::collections::VecDeque::new();
937 queue.push_back(start);
938 while let Some(node) = queue.pop_front() {
939 if node >= self.n || visited[node] {
940 continue;
941 }
942 visited[node] = true;
943 for &next in &self.adj[node] {
944 queue.push_back(next);
945 }
946 }
947 (0..self.n).filter(|&i| visited[i]).collect()
948 }
949 pub fn can_reach(&self, from: usize, to: usize) -> bool {
951 self.reachable_from(from).contains(&to)
952 }
953}
954#[allow(dead_code)]
956pub struct PathBuf {
957 components: Vec<String>,
958}
959#[allow(dead_code)]
960impl PathBuf {
961 pub fn new() -> Self {
963 Self {
964 components: Vec::new(),
965 }
966 }
967 pub fn push(&mut self, comp: impl Into<String>) {
969 self.components.push(comp.into());
970 }
971 pub fn pop(&mut self) {
973 self.components.pop();
974 }
975 pub fn as_str(&self) -> String {
977 self.components.join("/")
978 }
979 pub fn depth(&self) -> usize {
981 self.components.len()
982 }
983 pub fn clear(&mut self) {
985 self.components.clear();
986 }
987}
988#[allow(dead_code)]
990pub struct SparseVec<T: Default + Clone + PartialEq> {
991 entries: std::collections::HashMap<usize, T>,
992 default_: T,
993 logical_len: usize,
994}
995#[allow(dead_code)]
996impl<T: Default + Clone + PartialEq> SparseVec<T> {
997 pub fn new(len: usize) -> Self {
999 Self {
1000 entries: std::collections::HashMap::new(),
1001 default_: T::default(),
1002 logical_len: len,
1003 }
1004 }
1005 pub fn set(&mut self, idx: usize, val: T) {
1007 if val == self.default_ {
1008 self.entries.remove(&idx);
1009 } else {
1010 self.entries.insert(idx, val);
1011 }
1012 }
1013 pub fn get(&self, idx: usize) -> &T {
1015 self.entries.get(&idx).unwrap_or(&self.default_)
1016 }
1017 pub fn len(&self) -> usize {
1019 self.logical_len
1020 }
1021 pub fn is_empty(&self) -> bool {
1023 self.len() == 0
1024 }
1025 pub fn nnz(&self) -> usize {
1027 self.entries.len()
1028 }
1029}
1030#[allow(dead_code)]
1032pub struct WindowIterator<'a, T> {
1033 pub(super) data: &'a [T],
1034 pub(super) pos: usize,
1035 pub(super) window: usize,
1036}
1037#[allow(dead_code)]
1038impl<'a, T> WindowIterator<'a, T> {
1039 pub fn new(data: &'a [T], window: usize) -> Self {
1041 Self {
1042 data,
1043 pos: 0,
1044 window,
1045 }
1046 }
1047}
1048#[allow(dead_code)]
1050pub struct StringPool {
1051 free: Vec<String>,
1052}
1053#[allow(dead_code)]
1054impl StringPool {
1055 pub fn new() -> Self {
1057 Self { free: Vec::new() }
1058 }
1059 pub fn take(&mut self) -> String {
1061 self.free.pop().unwrap_or_default()
1062 }
1063 pub fn give(&mut self, mut s: String) {
1065 s.clear();
1066 self.free.push(s);
1067 }
1068 pub fn free_count(&self) -> usize {
1070 self.free.len()
1071 }
1072}
1073#[allow(dead_code)]
1075pub struct BitSet64 {
1076 bits: u64,
1077}
1078#[allow(dead_code)]
1079impl BitSet64 {
1080 pub const fn new() -> Self {
1082 Self { bits: 0 }
1083 }
1084 pub fn insert(&mut self, i: u32) {
1086 if i < 64 {
1087 self.bits |= 1u64 << i;
1088 }
1089 }
1090 pub fn remove(&mut self, i: u32) {
1092 if i < 64 {
1093 self.bits &= !(1u64 << i);
1094 }
1095 }
1096 pub fn contains(&self, i: u32) -> bool {
1098 i < 64 && (self.bits >> i) & 1 != 0
1099 }
1100 pub fn len(&self) -> u32 {
1102 self.bits.count_ones()
1103 }
1104 pub fn is_empty(&self) -> bool {
1106 self.bits == 0
1107 }
1108 pub fn union(self, other: BitSet64) -> BitSet64 {
1110 BitSet64 {
1111 bits: self.bits | other.bits,
1112 }
1113 }
1114 pub fn intersect(self, other: BitSet64) -> BitSet64 {
1116 BitSet64 {
1117 bits: self.bits & other.bits,
1118 }
1119 }
1120}
1121#[allow(dead_code)]
1123pub struct PrefixCounter {
1124 children: std::collections::HashMap<char, PrefixCounter>,
1125 count: usize,
1126}
1127#[allow(dead_code)]
1128impl PrefixCounter {
1129 pub fn new() -> Self {
1131 Self {
1132 children: std::collections::HashMap::new(),
1133 count: 0,
1134 }
1135 }
1136 pub fn record(&mut self, s: &str) {
1138 self.count += 1;
1139 let mut node = self;
1140 for c in s.chars() {
1141 node = node.children.entry(c).or_default();
1142 node.count += 1;
1143 }
1144 }
1145 pub fn count_with_prefix(&self, prefix: &str) -> usize {
1147 let mut node = self;
1148 for c in prefix.chars() {
1149 match node.children.get(&c) {
1150 Some(n) => node = n,
1151 None => return 0,
1152 }
1153 }
1154 node.count
1155 }
1156}
1157#[allow(dead_code)]
1159#[allow(missing_docs)]
1160pub struct RewriteRule {
1161 pub name: String,
1163 pub lhs: String,
1165 pub rhs: String,
1167 pub conditional: bool,
1169}
1170#[allow(dead_code)]
1171impl RewriteRule {
1172 pub fn unconditional(
1174 name: impl Into<String>,
1175 lhs: impl Into<String>,
1176 rhs: impl Into<String>,
1177 ) -> Self {
1178 Self {
1179 name: name.into(),
1180 lhs: lhs.into(),
1181 rhs: rhs.into(),
1182 conditional: false,
1183 }
1184 }
1185 pub fn conditional(
1187 name: impl Into<String>,
1188 lhs: impl Into<String>,
1189 rhs: impl Into<String>,
1190 ) -> Self {
1191 Self {
1192 name: name.into(),
1193 lhs: lhs.into(),
1194 rhs: rhs.into(),
1195 conditional: true,
1196 }
1197 }
1198 pub fn display(&self) -> String {
1200 format!("{}: {} → {}", self.name, self.lhs, self.rhs)
1201 }
1202}
1203#[derive(Default)]
1205#[allow(dead_code)]
1206pub struct CoercionTable {
1207 coercions: Vec<Coercion>,
1208}
1209impl CoercionTable {
1210 pub fn new() -> Self {
1212 Self {
1213 coercions: Vec::new(),
1214 }
1215 }
1216 pub fn register(&mut self, coercion: Coercion) {
1218 let pos = self
1219 .coercions
1220 .partition_point(|c| c.priority >= coercion.priority);
1221 self.coercions.insert(pos, coercion);
1222 }
1223 pub fn find(&self, source_head: &crate::Name) -> Vec<&Coercion> {
1225 self.coercions
1226 .iter()
1227 .filter(|c| coercion_head_matches(&c.source, source_head))
1228 .collect()
1229 }
1230 pub fn len(&self) -> usize {
1232 self.coercions.len()
1233 }
1234 pub fn is_empty(&self) -> bool {
1236 self.coercions.is_empty()
1237 }
1238 pub fn clear(&mut self) {
1240 self.coercions.clear();
1241 }
1242}
1243#[allow(dead_code)]
1245pub enum Either2<A, B> {
1246 First(A),
1248 Second(B),
1250}
1251#[allow(dead_code)]
1252impl<A, B> Either2<A, B> {
1253 pub fn is_first(&self) -> bool {
1255 matches!(self, Either2::First(_))
1256 }
1257 pub fn is_second(&self) -> bool {
1259 matches!(self, Either2::Second(_))
1260 }
1261 pub fn first(self) -> Option<A> {
1263 match self {
1264 Either2::First(a) => Some(a),
1265 _ => None,
1266 }
1267 }
1268 pub fn second(self) -> Option<B> {
1270 match self {
1271 Either2::Second(b) => Some(b),
1272 _ => None,
1273 }
1274 }
1275 pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
1277 match self {
1278 Either2::First(a) => Either2::First(f(a)),
1279 Either2::Second(b) => Either2::Second(b),
1280 }
1281 }
1282}
1283#[allow(dead_code)]
1285pub struct FocusStack<T> {
1286 items: Vec<T>,
1287}
1288#[allow(dead_code)]
1289impl<T> FocusStack<T> {
1290 pub fn new() -> Self {
1292 Self { items: Vec::new() }
1293 }
1294 pub fn focus(&mut self, item: T) {
1296 self.items.push(item);
1297 }
1298 pub fn blur(&mut self) -> Option<T> {
1300 self.items.pop()
1301 }
1302 pub fn current(&self) -> Option<&T> {
1304 self.items.last()
1305 }
1306 pub fn depth(&self) -> usize {
1308 self.items.len()
1309 }
1310 pub fn is_empty(&self) -> bool {
1312 self.items.is_empty()
1313 }
1314}
1315#[allow(dead_code)]
1317pub struct RawFnPtr {
1318 ptr: usize,
1320 arity: usize,
1321 name: String,
1322}
1323#[allow(dead_code)]
1324impl RawFnPtr {
1325 pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
1327 Self {
1328 ptr,
1329 arity,
1330 name: name.into(),
1331 }
1332 }
1333 pub fn arity(&self) -> usize {
1335 self.arity
1336 }
1337 pub fn name(&self) -> &str {
1339 &self.name
1340 }
1341 pub fn raw(&self) -> usize {
1343 self.ptr
1344 }
1345}
1346#[allow(dead_code)]
1348pub struct Stopwatch {
1349 start: crate::wall_clock::Instant,
1350 splits: Vec<f64>,
1351}
1352#[allow(dead_code)]
1353impl Stopwatch {
1354 pub fn start() -> Self {
1356 Self {
1357 start: crate::wall_clock::Instant::now(),
1358 splits: Vec::new(),
1359 }
1360 }
1361 pub fn split(&mut self) {
1363 self.splits.push(self.elapsed_ms());
1364 }
1365 pub fn elapsed_ms(&self) -> f64 {
1367 self.start.elapsed().as_secs_f64() * 1000.0
1368 }
1369 pub fn splits(&self) -> &[f64] {
1371 &self.splits
1372 }
1373 pub fn num_splits(&self) -> usize {
1375 self.splits.len()
1376 }
1377}
1378#[allow(dead_code)]
1380pub struct Fixture {
1381 data: std::collections::HashMap<String, String>,
1382}
1383#[allow(dead_code)]
1384impl Fixture {
1385 pub fn new() -> Self {
1387 Self {
1388 data: std::collections::HashMap::new(),
1389 }
1390 }
1391 pub fn set(&mut self, key: impl Into<String>, val: impl Into<String>) {
1393 self.data.insert(key.into(), val.into());
1394 }
1395 pub fn get(&self, key: &str) -> Option<&str> {
1397 self.data.get(key).map(|s| s.as_str())
1398 }
1399 pub fn len(&self) -> usize {
1401 self.data.len()
1402 }
1403 pub fn is_empty(&self) -> bool {
1405 self.len() == 0
1406 }
1407}
1408#[allow(dead_code)]
1410pub struct TransformStat {
1411 before: StatSummary,
1412 after: StatSummary,
1413}
1414#[allow(dead_code)]
1415impl TransformStat {
1416 pub fn new() -> Self {
1418 Self {
1419 before: StatSummary::new(),
1420 after: StatSummary::new(),
1421 }
1422 }
1423 pub fn record_before(&mut self, v: f64) {
1425 self.before.record(v);
1426 }
1427 pub fn record_after(&mut self, v: f64) {
1429 self.after.record(v);
1430 }
1431 pub fn mean_ratio(&self) -> Option<f64> {
1433 let b = self.before.mean()?;
1434 let a = self.after.mean()?;
1435 if b.abs() < f64::EPSILON {
1436 return None;
1437 }
1438 Some(a / b)
1439 }
1440}
1441#[allow(dead_code)]
1443pub struct BucketCounter<const N: usize> {
1444 buckets: [u64; N],
1445}
1446#[allow(dead_code)]
1447impl<const N: usize> BucketCounter<N> {
1448 pub const fn new() -> Self {
1450 Self { buckets: [0u64; N] }
1451 }
1452 pub fn inc(&mut self, i: usize) {
1454 if i < N {
1455 self.buckets[i] += 1;
1456 }
1457 }
1458 pub fn get(&self, i: usize) -> u64 {
1460 if i < N {
1461 self.buckets[i]
1462 } else {
1463 0
1464 }
1465 }
1466 pub fn total(&self) -> u64 {
1468 self.buckets.iter().sum()
1469 }
1470 pub fn argmax(&self) -> usize {
1472 self.buckets
1473 .iter()
1474 .enumerate()
1475 .max_by_key(|(_, &v)| v)
1476 .map(|(i, _)| i)
1477 .unwrap_or(0)
1478 }
1479}
1480#[allow(dead_code)]
1482pub struct LabelSet {
1483 labels: Vec<String>,
1484}
1485#[allow(dead_code)]
1486impl LabelSet {
1487 pub fn new() -> Self {
1489 Self { labels: Vec::new() }
1490 }
1491 pub fn add(&mut self, label: impl Into<String>) {
1493 let s = label.into();
1494 if !self.labels.contains(&s) {
1495 self.labels.push(s);
1496 }
1497 }
1498 pub fn has(&self, label: &str) -> bool {
1500 self.labels.iter().any(|l| l == label)
1501 }
1502 pub fn count(&self) -> usize {
1504 self.labels.len()
1505 }
1506 pub fn all(&self) -> &[String] {
1508 &self.labels
1509 }
1510}