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: crate::wall_clock::Instant,
47 splits: Vec<f64>,
48}
49#[allow(dead_code)]
50impl Stopwatch {
51 pub fn start() -> Self {
53 Self {
54 start: crate::wall_clock::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: crate::wall_clock::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: crate::wall_clock::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 = crate::wall_clock::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 earlier: Vec<T>,
510 current: T,
512}
513#[allow(dead_code)]
514impl<T: Clone> VersionedRecord<T> {
515 pub fn new(initial: T) -> Self {
517 Self {
518 earlier: Vec::new(),
519 current: initial,
520 }
521 }
522 pub fn update(&mut self, val: T) {
524 let previous = std::mem::replace(&mut self.current, val);
525 self.earlier.push(previous);
526 }
527 pub fn current(&self) -> &T {
529 &self.current
530 }
531 pub fn at_version(&self, n: usize) -> Option<&T> {
533 match self.earlier.get(n) {
534 Some(value) => Some(value),
535 None if n == self.earlier.len() => Some(&self.current),
536 None => None,
537 }
538 }
539 pub fn version(&self) -> usize {
541 self.earlier.len()
542 }
543 pub fn has_history(&self) -> bool {
545 !self.earlier.is_empty()
546 }
547}
548#[allow(dead_code)]
550pub struct SlidingSum {
551 window: Vec<f64>,
552 capacity: usize,
553 pos: usize,
554 sum: f64,
555 count: usize,
556}
557#[allow(dead_code)]
558impl SlidingSum {
559 pub fn new(capacity: usize) -> Self {
561 Self {
562 window: vec![0.0; capacity],
563 capacity,
564 pos: 0,
565 sum: 0.0,
566 count: 0,
567 }
568 }
569 pub fn push(&mut self, val: f64) {
571 let oldest = self.window[self.pos];
572 self.sum -= oldest;
573 self.sum += val;
574 self.window[self.pos] = val;
575 self.pos = (self.pos + 1) % self.capacity;
576 if self.count < self.capacity {
577 self.count += 1;
578 }
579 }
580 pub fn sum(&self) -> f64 {
582 self.sum
583 }
584 pub fn mean(&self) -> Option<f64> {
586 if self.count == 0 {
587 None
588 } else {
589 Some(self.sum / self.count as f64)
590 }
591 }
592 pub fn count(&self) -> usize {
594 self.count
595 }
596}
597#[allow(dead_code)]
599pub struct MinHeap<T: Ord> {
600 data: Vec<T>,
601}
602#[allow(dead_code)]
603impl<T: Ord> MinHeap<T> {
604 pub fn new() -> Self {
606 Self { data: Vec::new() }
607 }
608 pub fn push(&mut self, val: T) {
610 self.data.push(val);
611 self.sift_up(self.data.len() - 1);
612 }
613 pub fn pop(&mut self) -> Option<T> {
615 if self.data.is_empty() {
616 return None;
617 }
618 let n = self.data.len();
619 self.data.swap(0, n - 1);
620 let min = self.data.pop();
621 if !self.data.is_empty() {
622 self.sift_down(0);
623 }
624 min
625 }
626 pub fn peek(&self) -> Option<&T> {
628 self.data.first()
629 }
630 pub fn len(&self) -> usize {
632 self.data.len()
633 }
634 pub fn is_empty(&self) -> bool {
636 self.data.is_empty()
637 }
638 fn sift_up(&mut self, mut i: usize) {
639 while i > 0 {
640 let parent = (i - 1) / 2;
641 if self.data[i] < self.data[parent] {
642 self.data.swap(i, parent);
643 i = parent;
644 } else {
645 break;
646 }
647 }
648 }
649 fn sift_down(&mut self, mut i: usize) {
650 let n = self.data.len();
651 loop {
652 let left = 2 * i + 1;
653 let right = 2 * i + 2;
654 let mut smallest = i;
655 if left < n && self.data[left] < self.data[smallest] {
656 smallest = left;
657 }
658 if right < n && self.data[right] < self.data[smallest] {
659 smallest = right;
660 }
661 if smallest == i {
662 break;
663 }
664 self.data.swap(i, smallest);
665 i = smallest;
666 }
667 }
668}
669#[allow(dead_code)]
671pub struct BucketCounter<const N: usize> {
672 buckets: [u64; N],
673}
674#[allow(dead_code)]
675impl<const N: usize> BucketCounter<N> {
676 pub const fn new() -> Self {
678 Self { buckets: [0u64; N] }
679 }
680 pub fn inc(&mut self, i: usize) {
682 if i < N {
683 self.buckets[i] += 1;
684 }
685 }
686 pub fn get(&self, i: usize) -> u64 {
688 if i < N {
689 self.buckets[i]
690 } else {
691 0
692 }
693 }
694 pub fn total(&self) -> u64 {
696 self.buckets.iter().sum()
697 }
698 pub fn argmax(&self) -> usize {
700 self.buckets
701 .iter()
702 .enumerate()
703 .max_by_key(|(_, &v)| v)
704 .map(|(i, _)| i)
705 .unwrap_or(0)
706 }
707}
708#[allow(dead_code)]
710pub struct LabelSet {
711 labels: Vec<String>,
712}
713#[allow(dead_code)]
714impl LabelSet {
715 pub fn new() -> Self {
717 Self { labels: Vec::new() }
718 }
719 pub fn add(&mut self, label: impl Into<String>) {
721 let s = label.into();
722 if !self.labels.contains(&s) {
723 self.labels.push(s);
724 }
725 }
726 pub fn has(&self, label: &str) -> bool {
728 self.labels.iter().any(|l| l == label)
729 }
730 pub fn count(&self) -> usize {
732 self.labels.len()
733 }
734 pub fn all(&self) -> &[String] {
736 &self.labels
737 }
738}
739#[allow(dead_code)]
741pub struct FocusStack<T> {
742 items: Vec<T>,
743}
744#[allow(dead_code)]
745impl<T> FocusStack<T> {
746 pub fn new() -> Self {
748 Self { items: Vec::new() }
749 }
750 pub fn focus(&mut self, item: T) {
752 self.items.push(item);
753 }
754 pub fn blur(&mut self) -> Option<T> {
756 self.items.pop()
757 }
758 pub fn current(&self) -> Option<&T> {
760 self.items.last()
761 }
762 pub fn depth(&self) -> usize {
764 self.items.len()
765 }
766 pub fn is_empty(&self) -> bool {
768 self.items.is_empty()
769 }
770}
771#[allow(dead_code)]
773pub struct SmallMap<K: Ord + Clone, V: Clone> {
774 entries: Vec<(K, V)>,
775}
776#[allow(dead_code)]
777impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
778 pub fn new() -> Self {
780 Self {
781 entries: Vec::new(),
782 }
783 }
784 pub fn insert(&mut self, key: K, val: V) {
786 match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
787 Ok(i) => self.entries[i].1 = val,
788 Err(i) => self.entries.insert(i, (key, val)),
789 }
790 }
791 pub fn get(&self, key: &K) -> Option<&V> {
793 self.entries
794 .binary_search_by_key(&key, |(k, _)| k)
795 .ok()
796 .map(|i| &self.entries[i].1)
797 }
798 pub fn len(&self) -> usize {
800 self.entries.len()
801 }
802 pub fn is_empty(&self) -> bool {
804 self.entries.is_empty()
805 }
806 pub fn keys(&self) -> Vec<&K> {
808 self.entries.iter().map(|(k, _)| k).collect()
809 }
810 pub fn values(&self) -> Vec<&V> {
812 self.entries.iter().map(|(_, v)| v).collect()
813 }
814}
815#[allow(dead_code)]
817pub struct WindowIterator<'a, T> {
818 pub(super) data: &'a [T],
819 pub(super) pos: usize,
820 pub(super) window: usize,
821}
822#[allow(dead_code)]
823impl<'a, T> WindowIterator<'a, T> {
824 pub fn new(data: &'a [T], window: usize) -> Self {
826 Self {
827 data,
828 pos: 0,
829 window,
830 }
831 }
832}
833#[allow(dead_code)]
835#[allow(missing_docs)]
836pub enum DecisionNode {
837 Leaf(String),
839 Branch {
841 key: String,
842 val: String,
843 yes_branch: Box<DecisionNode>,
844 no_branch: Box<DecisionNode>,
845 },
846}
847#[allow(dead_code)]
848impl DecisionNode {
849 pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
851 match self {
852 DecisionNode::Leaf(action) => action.as_str(),
853 DecisionNode::Branch {
854 key,
855 val,
856 yes_branch,
857 no_branch,
858 } => {
859 let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
860 if actual == val.as_str() {
861 yes_branch.evaluate(ctx)
862 } else {
863 no_branch.evaluate(ctx)
864 }
865 }
866 }
867 }
868 pub fn depth(&self) -> usize {
870 match self {
871 DecisionNode::Leaf(_) => 0,
872 DecisionNode::Branch {
873 yes_branch,
874 no_branch,
875 ..
876 } => 1 + yes_branch.depth().max(no_branch.depth()),
877 }
878 }
879}
880#[allow(dead_code)]
882pub struct RawFnPtr {
883 ptr: usize,
885 arity: usize,
886 name: String,
887}
888#[allow(dead_code)]
889impl RawFnPtr {
890 pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
892 Self {
893 ptr,
894 arity,
895 name: name.into(),
896 }
897 }
898 pub fn arity(&self) -> usize {
900 self.arity
901 }
902 pub fn name(&self) -> &str {
904 &self.name
905 }
906 pub fn raw(&self) -> usize {
908 self.ptr
909 }
910}
911#[allow(dead_code)]
913pub struct WriteOnce<T> {
914 value: std::cell::Cell<Option<T>>,
915}
916#[allow(dead_code)]
917impl<T: Copy> WriteOnce<T> {
918 pub fn new() -> Self {
920 Self {
921 value: std::cell::Cell::new(None),
922 }
923 }
924 pub fn write(&self, val: T) -> bool {
926 if self.value.get().is_some() {
927 return false;
928 }
929 self.value.set(Some(val));
930 true
931 }
932 pub fn read(&self) -> Option<T> {
934 self.value.get()
935 }
936 pub fn is_written(&self) -> bool {
938 self.value.get().is_some()
939 }
940}
941#[allow(dead_code)]
943pub struct SparseVec<T: Default + Clone + PartialEq> {
944 entries: std::collections::HashMap<usize, T>,
945 default_: T,
946 logical_len: usize,
947}
948#[allow(dead_code)]
949impl<T: Default + Clone + PartialEq> SparseVec<T> {
950 pub fn new(len: usize) -> Self {
952 Self {
953 entries: std::collections::HashMap::new(),
954 default_: T::default(),
955 logical_len: len,
956 }
957 }
958 pub fn set(&mut self, idx: usize, val: T) {
960 if val == self.default_ {
961 self.entries.remove(&idx);
962 } else {
963 self.entries.insert(idx, val);
964 }
965 }
966 pub fn get(&self, idx: usize) -> &T {
968 self.entries.get(&idx).unwrap_or(&self.default_)
969 }
970 pub fn len(&self) -> usize {
972 self.logical_len
973 }
974 pub fn is_empty(&self) -> bool {
976 self.len() == 0
977 }
978 pub fn nnz(&self) -> usize {
980 self.entries.len()
981 }
982}
983#[allow(dead_code)]
985pub struct StackCalc {
986 stack: Vec<i64>,
987}
988#[allow(dead_code)]
989impl StackCalc {
990 pub fn new() -> Self {
992 Self { stack: Vec::new() }
993 }
994 pub fn push(&mut self, n: i64) {
996 self.stack.push(n);
997 }
998 fn apply_binary(&mut self, op: impl FnOnce(i64, i64) -> i64) -> Option<i64> {
1002 let (rest_len, a, b) = match self.stack[..] {
1003 [ref rest @ .., a, b] => (rest.len(), a, b),
1004 _ => return None,
1005 };
1006 let value = op(a, b);
1007 self.stack.truncate(rest_len);
1008 self.stack.push(value);
1009 Some(value)
1010 }
1011 pub fn add(&mut self) -> Option<i64> {
1015 self.apply_binary(|a, b| a + b)
1016 }
1017 pub fn sub(&mut self) -> Option<i64> {
1021 self.apply_binary(|a, b| a - b)
1022 }
1023 pub fn mul(&mut self) -> Option<i64> {
1027 self.apply_binary(|a, b| a * b)
1028 }
1029 pub fn peek(&self) -> Option<i64> {
1031 self.stack.last().copied()
1032 }
1033 pub fn depth(&self) -> usize {
1035 self.stack.len()
1036 }
1037}
1038#[allow(dead_code)]
1040pub struct TransitiveClosure {
1041 adj: Vec<Vec<usize>>,
1042 n: usize,
1043}
1044#[allow(dead_code)]
1045impl TransitiveClosure {
1046 pub fn new(n: usize) -> Self {
1048 Self {
1049 adj: vec![Vec::new(); n],
1050 n,
1051 }
1052 }
1053 pub fn add_edge(&mut self, from: usize, to: usize) {
1055 if from < self.n {
1056 self.adj[from].push(to);
1057 }
1058 }
1059 pub fn reachable_from(&self, start: usize) -> Vec<usize> {
1061 let mut visited = vec![false; self.n];
1062 let mut queue = std::collections::VecDeque::new();
1063 queue.push_back(start);
1064 while let Some(node) = queue.pop_front() {
1065 if node >= self.n || visited[node] {
1066 continue;
1067 }
1068 visited[node] = true;
1069 for &next in &self.adj[node] {
1070 queue.push_back(next);
1071 }
1072 }
1073 (0..self.n).filter(|&i| visited[i]).collect()
1074 }
1075 pub fn can_reach(&self, from: usize, to: usize) -> bool {
1077 self.reachable_from(from).contains(&to)
1078 }
1079}
1080#[allow(dead_code)]
1082pub struct SimpleDag {
1083 edges: Vec<Vec<usize>>,
1085}
1086#[allow(dead_code)]
1087impl SimpleDag {
1088 pub fn new(n: usize) -> Self {
1090 Self {
1091 edges: vec![Vec::new(); n],
1092 }
1093 }
1094 pub fn add_edge(&mut self, from: usize, to: usize) {
1096 if from < self.edges.len() {
1097 self.edges[from].push(to);
1098 }
1099 }
1100 pub fn successors(&self, node: usize) -> &[usize] {
1102 self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
1103 }
1104 pub fn can_reach(&self, from: usize, to: usize) -> bool {
1106 let mut visited = vec![false; self.edges.len()];
1107 self.dfs(from, to, &mut visited)
1108 }
1109 fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
1110 if cur == target {
1111 return true;
1112 }
1113 if cur >= visited.len() || visited[cur] {
1114 return false;
1115 }
1116 visited[cur] = true;
1117 for &next in self.successors(cur) {
1118 if self.dfs(next, target, visited) {
1119 return true;
1120 }
1121 }
1122 false
1123 }
1124 pub fn topological_sort(&self) -> Option<Vec<usize>> {
1126 let n = self.edges.len();
1127 let mut in_degree = vec![0usize; n];
1128 for succs in &self.edges {
1129 for &s in succs {
1130 if s < n {
1131 in_degree[s] += 1;
1132 }
1133 }
1134 }
1135 let mut queue: std::collections::VecDeque<usize> =
1136 (0..n).filter(|&i| in_degree[i] == 0).collect();
1137 let mut order = Vec::new();
1138 while let Some(node) = queue.pop_front() {
1139 order.push(node);
1140 for &s in self.successors(node) {
1141 if s < n {
1142 in_degree[s] -= 1;
1143 if in_degree[s] == 0 {
1144 queue.push_back(s);
1145 }
1146 }
1147 }
1148 }
1149 if order.len() == n {
1150 Some(order)
1151 } else {
1152 None
1153 }
1154 }
1155 pub fn num_nodes(&self) -> usize {
1157 self.edges.len()
1158 }
1159}
1160#[allow(dead_code)]
1162pub struct ConfigNode {
1163 key: String,
1164 value: Option<String>,
1165 children: Vec<ConfigNode>,
1166}
1167#[allow(dead_code)]
1168impl ConfigNode {
1169 pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
1171 Self {
1172 key: key.into(),
1173 value: Some(value.into()),
1174 children: Vec::new(),
1175 }
1176 }
1177 pub fn section(key: impl Into<String>) -> Self {
1179 Self {
1180 key: key.into(),
1181 value: None,
1182 children: Vec::new(),
1183 }
1184 }
1185 pub fn add_child(&mut self, child: ConfigNode) {
1187 self.children.push(child);
1188 }
1189 pub fn key(&self) -> &str {
1191 &self.key
1192 }
1193 pub fn value(&self) -> Option<&str> {
1195 self.value.as_deref()
1196 }
1197 pub fn num_children(&self) -> usize {
1199 self.children.len()
1200 }
1201 pub fn lookup(&self, path: &str) -> Option<&str> {
1203 let mut parts = path.splitn(2, '.');
1204 let head = parts.next()?;
1205 let tail = parts.next();
1206 if head != self.key {
1207 return None;
1208 }
1209 match tail {
1210 None => self.value.as_deref(),
1211 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
1212 }
1213 }
1214 fn lookup_relative(&self, path: &str) -> Option<&str> {
1215 let mut parts = path.splitn(2, '.');
1216 let head = parts.next()?;
1217 let tail = parts.next();
1218 if head != self.key {
1219 return None;
1220 }
1221 match tail {
1222 None => self.value.as_deref(),
1223 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
1224 }
1225 }
1226}
1227#[allow(dead_code)]
1229pub struct StatSummary {
1230 count: u64,
1231 sum: f64,
1232 min: f64,
1233 max: f64,
1234}
1235#[allow(dead_code)]
1236impl StatSummary {
1237 pub fn new() -> Self {
1239 Self {
1240 count: 0,
1241 sum: 0.0,
1242 min: f64::INFINITY,
1243 max: f64::NEG_INFINITY,
1244 }
1245 }
1246 pub fn record(&mut self, val: f64) {
1248 self.count += 1;
1249 self.sum += val;
1250 if val < self.min {
1251 self.min = val;
1252 }
1253 if val > self.max {
1254 self.max = val;
1255 }
1256 }
1257 pub fn mean(&self) -> Option<f64> {
1259 if self.count == 0 {
1260 None
1261 } else {
1262 Some(self.sum / self.count as f64)
1263 }
1264 }
1265 pub fn min(&self) -> Option<f64> {
1267 if self.count == 0 {
1268 None
1269 } else {
1270 Some(self.min)
1271 }
1272 }
1273 pub fn max(&self) -> Option<f64> {
1275 if self.count == 0 {
1276 None
1277 } else {
1278 Some(self.max)
1279 }
1280 }
1281 pub fn count(&self) -> u64 {
1283 self.count
1284 }
1285}
1286#[allow(dead_code)]
1288pub struct Fixture {
1289 data: std::collections::HashMap<String, String>,
1290}
1291#[allow(dead_code)]
1292impl Fixture {
1293 pub fn new() -> Self {
1295 Self {
1296 data: std::collections::HashMap::new(),
1297 }
1298 }
1299 pub fn set(&mut self, key: impl Into<String>, val: impl Into<String>) {
1301 self.data.insert(key.into(), val.into());
1302 }
1303 pub fn get(&self, key: &str) -> Option<&str> {
1305 self.data.get(key).map(|s| s.as_str())
1306 }
1307 pub fn len(&self) -> usize {
1309 self.data.len()
1310 }
1311 pub fn is_empty(&self) -> bool {
1313 self.len() == 0
1314 }
1315}