1use crate::Expr;
6
7use std::collections::HashMap;
8
9use super::functions::apply_subst;
10
11#[allow(dead_code)]
13pub struct FlatSubstitution {
14 pairs: Vec<(String, String)>,
15}
16#[allow(dead_code)]
17impl FlatSubstitution {
18 pub fn new() -> Self {
20 Self { pairs: Vec::new() }
21 }
22 pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
24 self.pairs.push((from.into(), to.into()));
25 }
26 pub fn apply(&self, s: &str) -> String {
28 let mut result = s.to_string();
29 for (from, to) in &self.pairs {
30 result = result.replace(from.as_str(), to.as_str());
31 }
32 result
33 }
34 pub fn len(&self) -> usize {
36 self.pairs.len()
37 }
38 pub fn is_empty(&self) -> bool {
40 self.pairs.is_empty()
41 }
42}
43#[allow(dead_code)]
45pub struct Stopwatch {
46 start: std::time::Instant,
47 splits: Vec<f64>,
48}
49#[allow(dead_code)]
50impl Stopwatch {
51 pub fn start() -> Self {
53 Self {
54 start: std::time::Instant::now(),
55 splits: Vec::new(),
56 }
57 }
58 pub fn split(&mut self) {
60 self.splits.push(self.elapsed_ms());
61 }
62 pub fn elapsed_ms(&self) -> f64 {
64 self.start.elapsed().as_secs_f64() * 1000.0
65 }
66 pub fn splits(&self) -> &[f64] {
68 &self.splits
69 }
70 pub fn num_splits(&self) -> usize {
72 self.splits.len()
73 }
74}
75#[derive(Debug, Clone, Default)]
79pub struct Substitution {
80 mapping: Vec<Option<Expr>>,
82}
83impl Substitution {
84 pub fn new() -> Self {
86 Self::default()
87 }
88 pub fn single(expr: Expr) -> Self {
90 Self {
91 mapping: vec![Some(expr)],
92 }
93 }
94 pub fn add(&mut self, level: usize, expr: Expr) {
96 if level >= self.mapping.len() {
97 self.mapping.resize(level + 1, None);
98 }
99 self.mapping[level] = Some(expr);
100 }
101 pub fn get(&self, level: u32) -> Option<&Expr> {
103 self.mapping.get(level as usize).and_then(|o| o.as_ref())
104 }
105 pub fn len(&self) -> usize {
107 self.mapping.len()
108 }
109 pub fn is_empty(&self) -> bool {
111 self.mapping.iter().all(|o| o.is_none())
112 }
113 pub fn apply(&self, expr: &Expr) -> Expr {
115 apply_subst(expr, self, 0)
116 }
117}
118#[allow(dead_code)]
120pub struct RewriteRuleSet {
121 rules: Vec<RewriteRule>,
122}
123#[allow(dead_code)]
124impl RewriteRuleSet {
125 pub fn new() -> Self {
127 Self { rules: Vec::new() }
128 }
129 pub fn add(&mut self, rule: RewriteRule) {
131 self.rules.push(rule);
132 }
133 pub fn len(&self) -> usize {
135 self.rules.len()
136 }
137 pub fn is_empty(&self) -> bool {
139 self.rules.is_empty()
140 }
141 pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
143 self.rules.iter().filter(|r| r.conditional).collect()
144 }
145 pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
147 self.rules.iter().filter(|r| !r.conditional).collect()
148 }
149 pub fn get(&self, name: &str) -> Option<&RewriteRule> {
151 self.rules.iter().find(|r| r.name == name)
152 }
153}
154#[allow(dead_code)]
156#[allow(missing_docs)]
157pub struct RewriteRule {
158 pub name: String,
160 pub lhs: String,
162 pub rhs: String,
164 pub conditional: bool,
166}
167#[allow(dead_code)]
168impl RewriteRule {
169 pub fn unconditional(
171 name: impl Into<String>,
172 lhs: impl Into<String>,
173 rhs: impl Into<String>,
174 ) -> Self {
175 Self {
176 name: name.into(),
177 lhs: lhs.into(),
178 rhs: rhs.into(),
179 conditional: false,
180 }
181 }
182 pub fn conditional(
184 name: impl Into<String>,
185 lhs: impl Into<String>,
186 rhs: impl Into<String>,
187 ) -> Self {
188 Self {
189 name: name.into(),
190 lhs: lhs.into(),
191 rhs: rhs.into(),
192 conditional: true,
193 }
194 }
195 pub fn display(&self) -> String {
197 format!("{}: {} → {}", self.name, self.lhs, self.rhs)
198 }
199}
200#[allow(dead_code)]
202pub struct TransformStat {
203 before: StatSummary,
204 after: StatSummary,
205}
206#[allow(dead_code)]
207impl TransformStat {
208 pub fn new() -> Self {
210 Self {
211 before: StatSummary::new(),
212 after: StatSummary::new(),
213 }
214 }
215 pub fn record_before(&mut self, v: f64) {
217 self.before.record(v);
218 }
219 pub fn record_after(&mut self, v: f64) {
221 self.after.record(v);
222 }
223 pub fn mean_ratio(&self) -> Option<f64> {
225 let b = self.before.mean()?;
226 let a = self.after.mean()?;
227 if b.abs() < f64::EPSILON {
228 return None;
229 }
230 Some(a / b)
231 }
232}
233#[allow(dead_code)]
235pub struct BitSet64 {
236 bits: u64,
237}
238#[allow(dead_code)]
239impl BitSet64 {
240 pub const fn new() -> Self {
242 Self { bits: 0 }
243 }
244 pub fn insert(&mut self, i: u32) {
246 if i < 64 {
247 self.bits |= 1u64 << i;
248 }
249 }
250 pub fn remove(&mut self, i: u32) {
252 if i < 64 {
253 self.bits &= !(1u64 << i);
254 }
255 }
256 pub fn contains(&self, i: u32) -> bool {
258 i < 64 && (self.bits >> i) & 1 != 0
259 }
260 pub fn len(&self) -> u32 {
262 self.bits.count_ones()
263 }
264 pub fn is_empty(&self) -> bool {
266 self.bits == 0
267 }
268 pub fn union(self, other: BitSet64) -> BitSet64 {
270 BitSet64 {
271 bits: self.bits | other.bits,
272 }
273 }
274 pub fn intersect(self, other: BitSet64) -> BitSet64 {
276 BitSet64 {
277 bits: self.bits & other.bits,
278 }
279 }
280}
281#[allow(dead_code)]
283pub struct TokenBucket {
284 capacity: u64,
285 tokens: u64,
286 refill_per_ms: u64,
287 last_refill: std::time::Instant,
288}
289#[allow(dead_code)]
290impl TokenBucket {
291 pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
293 Self {
294 capacity,
295 tokens: capacity,
296 refill_per_ms,
297 last_refill: std::time::Instant::now(),
298 }
299 }
300 pub fn try_consume(&mut self, n: u64) -> bool {
302 self.refill();
303 if self.tokens >= n {
304 self.tokens -= n;
305 true
306 } else {
307 false
308 }
309 }
310 fn refill(&mut self) {
311 let now = std::time::Instant::now();
312 let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
313 if elapsed_ms > 0 {
314 let new_tokens = elapsed_ms * self.refill_per_ms;
315 self.tokens = (self.tokens + new_tokens).min(self.capacity);
316 self.last_refill = now;
317 }
318 }
319 pub fn available(&self) -> u64 {
321 self.tokens
322 }
323 pub fn capacity(&self) -> u64 {
325 self.capacity
326 }
327}
328#[allow(dead_code)]
330pub struct PathBuf {
331 components: Vec<String>,
332}
333#[allow(dead_code)]
334impl PathBuf {
335 pub fn new() -> Self {
337 Self {
338 components: Vec::new(),
339 }
340 }
341 pub fn push(&mut self, comp: impl Into<String>) {
343 self.components.push(comp.into());
344 }
345 pub fn pop(&mut self) {
347 self.components.pop();
348 }
349 pub fn as_str(&self) -> String {
351 self.components.join("/")
352 }
353 pub fn depth(&self) -> usize {
355 self.components.len()
356 }
357 pub fn clear(&mut self) {
359 self.components.clear();
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#[allow(dead_code)]
431pub struct PrefixCounter {
432 children: std::collections::HashMap<char, PrefixCounter>,
433 count: usize,
434}
435#[allow(dead_code)]
436impl PrefixCounter {
437 pub fn new() -> Self {
439 Self {
440 children: std::collections::HashMap::new(),
441 count: 0,
442 }
443 }
444 pub fn record(&mut self, s: &str) {
446 self.count += 1;
447 let mut node = self;
448 for c in s.chars() {
449 node = node.children.entry(c).or_default();
450 node.count += 1;
451 }
452 }
453 pub fn count_with_prefix(&self, prefix: &str) -> usize {
455 let mut node = self;
456 for c in prefix.chars() {
457 match node.children.get(&c) {
458 Some(n) => node = n,
459 None => return 0,
460 }
461 }
462 node.count
463 }
464}
465#[allow(dead_code)]
467pub enum Either2<A, B> {
468 First(A),
470 Second(B),
472}
473#[allow(dead_code)]
474impl<A, B> Either2<A, B> {
475 pub fn is_first(&self) -> bool {
477 matches!(self, Either2::First(_))
478 }
479 pub fn is_second(&self) -> bool {
481 matches!(self, Either2::Second(_))
482 }
483 pub fn first(self) -> Option<A> {
485 match self {
486 Either2::First(a) => Some(a),
487 _ => None,
488 }
489 }
490 pub fn second(self) -> Option<B> {
492 match self {
493 Either2::Second(b) => Some(b),
494 _ => None,
495 }
496 }
497 pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
499 match self {
500 Either2::First(a) => Either2::First(f(a)),
501 Either2::Second(b) => Either2::Second(b),
502 }
503 }
504}
505#[allow(dead_code)]
507pub struct VersionedRecord<T: Clone> {
508 history: Vec<T>,
509}
510#[allow(dead_code)]
511impl<T: Clone> VersionedRecord<T> {
512 pub fn new(initial: T) -> Self {
514 Self {
515 history: vec![initial],
516 }
517 }
518 pub fn update(&mut self, val: T) {
520 self.history.push(val);
521 }
522 pub fn current(&self) -> &T {
524 self.history
525 .last()
526 .expect("VersionedRecord history is always non-empty after construction")
527 }
528 pub fn at_version(&self, n: usize) -> Option<&T> {
530 self.history.get(n)
531 }
532 pub fn version(&self) -> usize {
534 self.history.len() - 1
535 }
536 pub fn has_history(&self) -> bool {
538 self.history.len() > 1
539 }
540}
541#[allow(dead_code)]
543pub struct SlidingSum {
544 window: Vec<f64>,
545 capacity: usize,
546 pos: usize,
547 sum: f64,
548 count: usize,
549}
550#[allow(dead_code)]
551impl SlidingSum {
552 pub fn new(capacity: usize) -> Self {
554 Self {
555 window: vec![0.0; capacity],
556 capacity,
557 pos: 0,
558 sum: 0.0,
559 count: 0,
560 }
561 }
562 pub fn push(&mut self, val: f64) {
564 let oldest = self.window[self.pos];
565 self.sum -= oldest;
566 self.sum += val;
567 self.window[self.pos] = val;
568 self.pos = (self.pos + 1) % self.capacity;
569 if self.count < self.capacity {
570 self.count += 1;
571 }
572 }
573 pub fn sum(&self) -> f64 {
575 self.sum
576 }
577 pub fn mean(&self) -> Option<f64> {
579 if self.count == 0 {
580 None
581 } else {
582 Some(self.sum / self.count as f64)
583 }
584 }
585 pub fn count(&self) -> usize {
587 self.count
588 }
589}
590#[allow(dead_code)]
592pub struct MinHeap<T: Ord> {
593 data: Vec<T>,
594}
595#[allow(dead_code)]
596impl<T: Ord> MinHeap<T> {
597 pub fn new() -> Self {
599 Self { data: Vec::new() }
600 }
601 pub fn push(&mut self, val: T) {
603 self.data.push(val);
604 self.sift_up(self.data.len() - 1);
605 }
606 pub fn pop(&mut self) -> Option<T> {
608 if self.data.is_empty() {
609 return None;
610 }
611 let n = self.data.len();
612 self.data.swap(0, n - 1);
613 let min = self.data.pop();
614 if !self.data.is_empty() {
615 self.sift_down(0);
616 }
617 min
618 }
619 pub fn peek(&self) -> Option<&T> {
621 self.data.first()
622 }
623 pub fn len(&self) -> usize {
625 self.data.len()
626 }
627 pub fn is_empty(&self) -> bool {
629 self.data.is_empty()
630 }
631 fn sift_up(&mut self, mut i: usize) {
632 while i > 0 {
633 let parent = (i - 1) / 2;
634 if self.data[i] < self.data[parent] {
635 self.data.swap(i, parent);
636 i = parent;
637 } else {
638 break;
639 }
640 }
641 }
642 fn sift_down(&mut self, mut i: usize) {
643 let n = self.data.len();
644 loop {
645 let left = 2 * i + 1;
646 let right = 2 * i + 2;
647 let mut smallest = i;
648 if left < n && self.data[left] < self.data[smallest] {
649 smallest = left;
650 }
651 if right < n && self.data[right] < self.data[smallest] {
652 smallest = right;
653 }
654 if smallest == i {
655 break;
656 }
657 self.data.swap(i, smallest);
658 i = smallest;
659 }
660 }
661}
662#[allow(dead_code)]
664pub struct BucketCounter<const N: usize> {
665 buckets: [u64; N],
666}
667#[allow(dead_code)]
668impl<const N: usize> BucketCounter<N> {
669 pub const fn new() -> Self {
671 Self { buckets: [0u64; N] }
672 }
673 pub fn inc(&mut self, i: usize) {
675 if i < N {
676 self.buckets[i] += 1;
677 }
678 }
679 pub fn get(&self, i: usize) -> u64 {
681 if i < N {
682 self.buckets[i]
683 } else {
684 0
685 }
686 }
687 pub fn total(&self) -> u64 {
689 self.buckets.iter().sum()
690 }
691 pub fn argmax(&self) -> usize {
693 self.buckets
694 .iter()
695 .enumerate()
696 .max_by_key(|(_, &v)| v)
697 .map(|(i, _)| i)
698 .unwrap_or(0)
699 }
700}
701#[allow(dead_code)]
703pub struct LabelSet {
704 labels: Vec<String>,
705}
706#[allow(dead_code)]
707impl LabelSet {
708 pub fn new() -> Self {
710 Self { labels: Vec::new() }
711 }
712 pub fn add(&mut self, label: impl Into<String>) {
714 let s = label.into();
715 if !self.labels.contains(&s) {
716 self.labels.push(s);
717 }
718 }
719 pub fn has(&self, label: &str) -> bool {
721 self.labels.iter().any(|l| l == label)
722 }
723 pub fn count(&self) -> usize {
725 self.labels.len()
726 }
727 pub fn all(&self) -> &[String] {
729 &self.labels
730 }
731}
732#[allow(dead_code)]
734pub struct FocusStack<T> {
735 items: Vec<T>,
736}
737#[allow(dead_code)]
738impl<T> FocusStack<T> {
739 pub fn new() -> Self {
741 Self { items: Vec::new() }
742 }
743 pub fn focus(&mut self, item: T) {
745 self.items.push(item);
746 }
747 pub fn blur(&mut self) -> Option<T> {
749 self.items.pop()
750 }
751 pub fn current(&self) -> Option<&T> {
753 self.items.last()
754 }
755 pub fn depth(&self) -> usize {
757 self.items.len()
758 }
759 pub fn is_empty(&self) -> bool {
761 self.items.is_empty()
762 }
763}
764#[allow(dead_code)]
766pub struct SmallMap<K: Ord + Clone, V: Clone> {
767 entries: Vec<(K, V)>,
768}
769#[allow(dead_code)]
770impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
771 pub fn new() -> Self {
773 Self {
774 entries: Vec::new(),
775 }
776 }
777 pub fn insert(&mut self, key: K, val: V) {
779 match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
780 Ok(i) => self.entries[i].1 = val,
781 Err(i) => self.entries.insert(i, (key, val)),
782 }
783 }
784 pub fn get(&self, key: &K) -> Option<&V> {
786 self.entries
787 .binary_search_by_key(&key, |(k, _)| k)
788 .ok()
789 .map(|i| &self.entries[i].1)
790 }
791 pub fn len(&self) -> usize {
793 self.entries.len()
794 }
795 pub fn is_empty(&self) -> bool {
797 self.entries.is_empty()
798 }
799 pub fn keys(&self) -> Vec<&K> {
801 self.entries.iter().map(|(k, _)| k).collect()
802 }
803 pub fn values(&self) -> Vec<&V> {
805 self.entries.iter().map(|(_, v)| v).collect()
806 }
807}
808#[allow(dead_code)]
810pub struct WindowIterator<'a, T> {
811 pub(super) data: &'a [T],
812 pub(super) pos: usize,
813 pub(super) window: usize,
814}
815#[allow(dead_code)]
816impl<'a, T> WindowIterator<'a, T> {
817 pub fn new(data: &'a [T], window: usize) -> Self {
819 Self {
820 data,
821 pos: 0,
822 window,
823 }
824 }
825}
826#[allow(dead_code)]
828#[allow(missing_docs)]
829pub enum DecisionNode {
830 Leaf(String),
832 Branch {
834 key: String,
835 val: String,
836 yes_branch: Box<DecisionNode>,
837 no_branch: Box<DecisionNode>,
838 },
839}
840#[allow(dead_code)]
841impl DecisionNode {
842 pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
844 match self {
845 DecisionNode::Leaf(action) => action.as_str(),
846 DecisionNode::Branch {
847 key,
848 val,
849 yes_branch,
850 no_branch,
851 } => {
852 let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
853 if actual == val.as_str() {
854 yes_branch.evaluate(ctx)
855 } else {
856 no_branch.evaluate(ctx)
857 }
858 }
859 }
860 }
861 pub fn depth(&self) -> usize {
863 match self {
864 DecisionNode::Leaf(_) => 0,
865 DecisionNode::Branch {
866 yes_branch,
867 no_branch,
868 ..
869 } => 1 + yes_branch.depth().max(no_branch.depth()),
870 }
871 }
872}
873#[allow(dead_code)]
875pub struct RawFnPtr {
876 ptr: usize,
878 arity: usize,
879 name: String,
880}
881#[allow(dead_code)]
882impl RawFnPtr {
883 pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
885 Self {
886 ptr,
887 arity,
888 name: name.into(),
889 }
890 }
891 pub fn arity(&self) -> usize {
893 self.arity
894 }
895 pub fn name(&self) -> &str {
897 &self.name
898 }
899 pub fn raw(&self) -> usize {
901 self.ptr
902 }
903}
904#[allow(dead_code)]
906pub struct WriteOnce<T> {
907 value: std::cell::Cell<Option<T>>,
908}
909#[allow(dead_code)]
910impl<T: Copy> WriteOnce<T> {
911 pub fn new() -> Self {
913 Self {
914 value: std::cell::Cell::new(None),
915 }
916 }
917 pub fn write(&self, val: T) -> bool {
919 if self.value.get().is_some() {
920 return false;
921 }
922 self.value.set(Some(val));
923 true
924 }
925 pub fn read(&self) -> Option<T> {
927 self.value.get()
928 }
929 pub fn is_written(&self) -> bool {
931 self.value.get().is_some()
932 }
933}
934#[allow(dead_code)]
936pub struct SparseVec<T: Default + Clone + PartialEq> {
937 entries: std::collections::HashMap<usize, T>,
938 default_: T,
939 logical_len: usize,
940}
941#[allow(dead_code)]
942impl<T: Default + Clone + PartialEq> SparseVec<T> {
943 pub fn new(len: usize) -> Self {
945 Self {
946 entries: std::collections::HashMap::new(),
947 default_: T::default(),
948 logical_len: len,
949 }
950 }
951 pub fn set(&mut self, idx: usize, val: T) {
953 if val == self.default_ {
954 self.entries.remove(&idx);
955 } else {
956 self.entries.insert(idx, val);
957 }
958 }
959 pub fn get(&self, idx: usize) -> &T {
961 self.entries.get(&idx).unwrap_or(&self.default_)
962 }
963 pub fn len(&self) -> usize {
965 self.logical_len
966 }
967 pub fn is_empty(&self) -> bool {
969 self.len() == 0
970 }
971 pub fn nnz(&self) -> usize {
973 self.entries.len()
974 }
975}
976#[allow(dead_code)]
978pub struct StackCalc {
979 stack: Vec<i64>,
980}
981#[allow(dead_code)]
982impl StackCalc {
983 pub fn new() -> Self {
985 Self { stack: Vec::new() }
986 }
987 pub fn push(&mut self, n: i64) {
989 self.stack.push(n);
990 }
991 pub fn add(&mut self) {
993 let b = self
994 .stack
995 .pop()
996 .expect("stack must have at least two values for add");
997 let a = self
998 .stack
999 .pop()
1000 .expect("stack must have at least two values for add");
1001 self.stack.push(a + b);
1002 }
1003 pub fn sub(&mut self) {
1005 let b = self
1006 .stack
1007 .pop()
1008 .expect("stack must have at least two values for sub");
1009 let a = self
1010 .stack
1011 .pop()
1012 .expect("stack must have at least two values for sub");
1013 self.stack.push(a - b);
1014 }
1015 pub fn mul(&mut self) {
1017 let b = self
1018 .stack
1019 .pop()
1020 .expect("stack must have at least two values for mul");
1021 let a = self
1022 .stack
1023 .pop()
1024 .expect("stack must have at least two values for mul");
1025 self.stack.push(a * b);
1026 }
1027 pub fn peek(&self) -> Option<i64> {
1029 self.stack.last().copied()
1030 }
1031 pub fn depth(&self) -> usize {
1033 self.stack.len()
1034 }
1035}
1036#[allow(dead_code)]
1038pub struct TransitiveClosure {
1039 adj: Vec<Vec<usize>>,
1040 n: usize,
1041}
1042#[allow(dead_code)]
1043impl TransitiveClosure {
1044 pub fn new(n: usize) -> Self {
1046 Self {
1047 adj: vec![Vec::new(); n],
1048 n,
1049 }
1050 }
1051 pub fn add_edge(&mut self, from: usize, to: usize) {
1053 if from < self.n {
1054 self.adj[from].push(to);
1055 }
1056 }
1057 pub fn reachable_from(&self, start: usize) -> Vec<usize> {
1059 let mut visited = vec![false; self.n];
1060 let mut queue = std::collections::VecDeque::new();
1061 queue.push_back(start);
1062 while let Some(node) = queue.pop_front() {
1063 if node >= self.n || visited[node] {
1064 continue;
1065 }
1066 visited[node] = true;
1067 for &next in &self.adj[node] {
1068 queue.push_back(next);
1069 }
1070 }
1071 (0..self.n).filter(|&i| visited[i]).collect()
1072 }
1073 pub fn can_reach(&self, from: usize, to: usize) -> bool {
1075 self.reachable_from(from).contains(&to)
1076 }
1077}
1078#[allow(dead_code)]
1080pub struct SimpleDag {
1081 edges: Vec<Vec<usize>>,
1083}
1084#[allow(dead_code)]
1085impl SimpleDag {
1086 pub fn new(n: usize) -> Self {
1088 Self {
1089 edges: vec![Vec::new(); n],
1090 }
1091 }
1092 pub fn add_edge(&mut self, from: usize, to: usize) {
1094 if from < self.edges.len() {
1095 self.edges[from].push(to);
1096 }
1097 }
1098 pub fn successors(&self, node: usize) -> &[usize] {
1100 self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
1101 }
1102 pub fn can_reach(&self, from: usize, to: usize) -> bool {
1104 let mut visited = vec![false; self.edges.len()];
1105 self.dfs(from, to, &mut visited)
1106 }
1107 fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
1108 if cur == target {
1109 return true;
1110 }
1111 if cur >= visited.len() || visited[cur] {
1112 return false;
1113 }
1114 visited[cur] = true;
1115 for &next in self.successors(cur) {
1116 if self.dfs(next, target, visited) {
1117 return true;
1118 }
1119 }
1120 false
1121 }
1122 pub fn topological_sort(&self) -> Option<Vec<usize>> {
1124 let n = self.edges.len();
1125 let mut in_degree = vec![0usize; n];
1126 for succs in &self.edges {
1127 for &s in succs {
1128 if s < n {
1129 in_degree[s] += 1;
1130 }
1131 }
1132 }
1133 let mut queue: std::collections::VecDeque<usize> =
1134 (0..n).filter(|&i| in_degree[i] == 0).collect();
1135 let mut order = Vec::new();
1136 while let Some(node) = queue.pop_front() {
1137 order.push(node);
1138 for &s in self.successors(node) {
1139 if s < n {
1140 in_degree[s] -= 1;
1141 if in_degree[s] == 0 {
1142 queue.push_back(s);
1143 }
1144 }
1145 }
1146 }
1147 if order.len() == n {
1148 Some(order)
1149 } else {
1150 None
1151 }
1152 }
1153 pub fn num_nodes(&self) -> usize {
1155 self.edges.len()
1156 }
1157}
1158#[allow(dead_code)]
1160pub struct ConfigNode {
1161 key: String,
1162 value: Option<String>,
1163 children: Vec<ConfigNode>,
1164}
1165#[allow(dead_code)]
1166impl ConfigNode {
1167 pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
1169 Self {
1170 key: key.into(),
1171 value: Some(value.into()),
1172 children: Vec::new(),
1173 }
1174 }
1175 pub fn section(key: impl Into<String>) -> Self {
1177 Self {
1178 key: key.into(),
1179 value: None,
1180 children: Vec::new(),
1181 }
1182 }
1183 pub fn add_child(&mut self, child: ConfigNode) {
1185 self.children.push(child);
1186 }
1187 pub fn key(&self) -> &str {
1189 &self.key
1190 }
1191 pub fn value(&self) -> Option<&str> {
1193 self.value.as_deref()
1194 }
1195 pub fn num_children(&self) -> usize {
1197 self.children.len()
1198 }
1199 pub fn lookup(&self, path: &str) -> Option<&str> {
1201 let mut parts = path.splitn(2, '.');
1202 let head = parts.next()?;
1203 let tail = parts.next();
1204 if head != self.key {
1205 return None;
1206 }
1207 match tail {
1208 None => self.value.as_deref(),
1209 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
1210 }
1211 }
1212 fn lookup_relative(&self, path: &str) -> Option<&str> {
1213 let mut parts = path.splitn(2, '.');
1214 let head = parts.next()?;
1215 let tail = parts.next();
1216 if head != self.key {
1217 return None;
1218 }
1219 match tail {
1220 None => self.value.as_deref(),
1221 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
1222 }
1223 }
1224}
1225#[allow(dead_code)]
1227pub struct StatSummary {
1228 count: u64,
1229 sum: f64,
1230 min: f64,
1231 max: f64,
1232}
1233#[allow(dead_code)]
1234impl StatSummary {
1235 pub fn new() -> Self {
1237 Self {
1238 count: 0,
1239 sum: 0.0,
1240 min: f64::INFINITY,
1241 max: f64::NEG_INFINITY,
1242 }
1243 }
1244 pub fn record(&mut self, val: f64) {
1246 self.count += 1;
1247 self.sum += val;
1248 if val < self.min {
1249 self.min = val;
1250 }
1251 if val > self.max {
1252 self.max = val;
1253 }
1254 }
1255 pub fn mean(&self) -> Option<f64> {
1257 if self.count == 0 {
1258 None
1259 } else {
1260 Some(self.sum / self.count as f64)
1261 }
1262 }
1263 pub fn min(&self) -> Option<f64> {
1265 if self.count == 0 {
1266 None
1267 } else {
1268 Some(self.min)
1269 }
1270 }
1271 pub fn max(&self) -> Option<f64> {
1273 if self.count == 0 {
1274 None
1275 } else {
1276 Some(self.max)
1277 }
1278 }
1279 pub fn count(&self) -> u64 {
1281 self.count
1282 }
1283}
1284#[allow(dead_code)]
1286pub struct Fixture {
1287 data: std::collections::HashMap<String, String>,
1288}
1289#[allow(dead_code)]
1290impl Fixture {
1291 pub fn new() -> Self {
1293 Self {
1294 data: std::collections::HashMap::new(),
1295 }
1296 }
1297 pub fn set(&mut self, key: impl Into<String>, val: impl Into<String>) {
1299 self.data.insert(key.into(), val.into());
1300 }
1301 pub fn get(&self, key: &str) -> Option<&str> {
1303 self.data.get(key).map(|s| s.as_str())
1304 }
1305 pub fn len(&self) -> usize {
1307 self.data.len()
1308 }
1309 pub fn is_empty(&self) -> bool {
1311 self.len() == 0
1312 }
1313}