1use super::functions::*;
6use crate::{Environment, Expr, Reducer};
7use std::collections::HashMap;
8
9#[allow(dead_code)]
11pub struct StatSummary {
12 count: u64,
13 sum: f64,
14 min: f64,
15 max: f64,
16}
17#[allow(dead_code)]
18impl StatSummary {
19 pub fn new() -> Self {
21 Self {
22 count: 0,
23 sum: 0.0,
24 min: f64::INFINITY,
25 max: f64::NEG_INFINITY,
26 }
27 }
28 pub fn record(&mut self, val: f64) {
30 self.count += 1;
31 self.sum += val;
32 if val < self.min {
33 self.min = val;
34 }
35 if val > self.max {
36 self.max = val;
37 }
38 }
39 pub fn mean(&self) -> Option<f64> {
41 if self.count == 0 {
42 None
43 } else {
44 Some(self.sum / self.count as f64)
45 }
46 }
47 pub fn min(&self) -> Option<f64> {
49 if self.count == 0 {
50 None
51 } else {
52 Some(self.min)
53 }
54 }
55 pub fn max(&self) -> Option<f64> {
57 if self.count == 0 {
58 None
59 } else {
60 Some(self.max)
61 }
62 }
63 pub fn count(&self) -> u64 {
65 self.count
66 }
67}
68#[allow(dead_code)]
70pub struct SparseVec<T: Default + Clone + PartialEq> {
71 entries: std::collections::HashMap<usize, T>,
72 default_: T,
73 logical_len: usize,
74}
75#[allow(dead_code)]
76impl<T: Default + Clone + PartialEq> SparseVec<T> {
77 pub fn new(len: usize) -> Self {
79 Self {
80 entries: std::collections::HashMap::new(),
81 default_: T::default(),
82 logical_len: len,
83 }
84 }
85 pub fn set(&mut self, idx: usize, val: T) {
87 if val == self.default_ {
88 self.entries.remove(&idx);
89 } else {
90 self.entries.insert(idx, val);
91 }
92 }
93 pub fn get(&self, idx: usize) -> &T {
95 self.entries.get(&idx).unwrap_or(&self.default_)
96 }
97 pub fn len(&self) -> usize {
99 self.logical_len
100 }
101 pub fn is_empty(&self) -> bool {
103 self.len() == 0
104 }
105 pub fn nnz(&self) -> usize {
107 self.entries.len()
108 }
109}
110#[allow(dead_code)]
112pub struct Stopwatch {
113 start: std::time::Instant,
114 splits: Vec<f64>,
115}
116#[allow(dead_code)]
117impl Stopwatch {
118 pub fn start() -> Self {
120 Self {
121 start: std::time::Instant::now(),
122 splits: Vec::new(),
123 }
124 }
125 pub fn split(&mut self) {
127 self.splits.push(self.elapsed_ms());
128 }
129 pub fn elapsed_ms(&self) -> f64 {
131 self.start.elapsed().as_secs_f64() * 1000.0
132 }
133 pub fn splits(&self) -> &[f64] {
135 &self.splits
136 }
137 pub fn num_splits(&self) -> usize {
139 self.splits.len()
140 }
141}
142#[allow(dead_code)]
144pub struct SmallMap<K: Ord + Clone, V: Clone> {
145 entries: Vec<(K, V)>,
146}
147#[allow(dead_code)]
148impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
149 pub fn new() -> Self {
151 Self {
152 entries: Vec::new(),
153 }
154 }
155 pub fn insert(&mut self, key: K, val: V) {
157 match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
158 Ok(i) => self.entries[i].1 = val,
159 Err(i) => self.entries.insert(i, (key, val)),
160 }
161 }
162 pub fn get(&self, key: &K) -> Option<&V> {
164 self.entries
165 .binary_search_by_key(&key, |(k, _)| k)
166 .ok()
167 .map(|i| &self.entries[i].1)
168 }
169 pub fn len(&self) -> usize {
171 self.entries.len()
172 }
173 pub fn is_empty(&self) -> bool {
175 self.entries.is_empty()
176 }
177 pub fn keys(&self) -> Vec<&K> {
179 self.entries.iter().map(|(k, _)| k).collect()
180 }
181 pub fn values(&self) -> Vec<&V> {
183 self.entries.iter().map(|(_, v)| v).collect()
184 }
185}
186#[allow(dead_code)]
188pub struct FocusStack<T> {
189 items: Vec<T>,
190}
191#[allow(dead_code)]
192impl<T> FocusStack<T> {
193 pub fn new() -> Self {
195 Self { items: Vec::new() }
196 }
197 pub fn focus(&mut self, item: T) {
199 self.items.push(item);
200 }
201 pub fn blur(&mut self) -> Option<T> {
203 self.items.pop()
204 }
205 pub fn current(&self) -> Option<&T> {
207 self.items.last()
208 }
209 pub fn depth(&self) -> usize {
211 self.items.len()
212 }
213 pub fn is_empty(&self) -> bool {
215 self.items.is_empty()
216 }
217}
218#[allow(dead_code)]
220pub struct TokenBucket {
221 capacity: u64,
222 tokens: u64,
223 refill_per_ms: u64,
224 last_refill: std::time::Instant,
225}
226#[allow(dead_code)]
227impl TokenBucket {
228 pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
230 Self {
231 capacity,
232 tokens: capacity,
233 refill_per_ms,
234 last_refill: std::time::Instant::now(),
235 }
236 }
237 pub fn try_consume(&mut self, n: u64) -> bool {
239 self.refill();
240 if self.tokens >= n {
241 self.tokens -= n;
242 true
243 } else {
244 false
245 }
246 }
247 fn refill(&mut self) {
248 let now = std::time::Instant::now();
249 let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
250 if elapsed_ms > 0 {
251 let new_tokens = elapsed_ms * self.refill_per_ms;
252 self.tokens = (self.tokens + new_tokens).min(self.capacity);
253 self.last_refill = now;
254 }
255 }
256 pub fn available(&self) -> u64 {
258 self.tokens
259 }
260 pub fn capacity(&self) -> u64 {
262 self.capacity
263 }
264}
265#[allow(dead_code)]
267#[allow(missing_docs)]
268pub enum DecisionNode {
269 Leaf(String),
271 Branch {
273 key: String,
274 val: String,
275 yes_branch: Box<DecisionNode>,
276 no_branch: Box<DecisionNode>,
277 },
278}
279#[allow(dead_code)]
280impl DecisionNode {
281 pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
283 match self {
284 DecisionNode::Leaf(action) => action.as_str(),
285 DecisionNode::Branch {
286 key,
287 val,
288 yes_branch,
289 no_branch,
290 } => {
291 let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
292 if actual == val.as_str() {
293 yes_branch.evaluate(ctx)
294 } else {
295 no_branch.evaluate(ctx)
296 }
297 }
298 }
299 }
300 pub fn depth(&self) -> usize {
302 match self {
303 DecisionNode::Leaf(_) => 0,
304 DecisionNode::Branch {
305 yes_branch,
306 no_branch,
307 ..
308 } => 1 + yes_branch.depth().max(no_branch.depth()),
309 }
310 }
311}
312#[allow(dead_code)]
314pub struct ConfigNode {
315 key: String,
316 value: Option<String>,
317 children: Vec<ConfigNode>,
318}
319#[allow(dead_code)]
320impl ConfigNode {
321 pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
323 Self {
324 key: key.into(),
325 value: Some(value.into()),
326 children: Vec::new(),
327 }
328 }
329 pub fn section(key: impl Into<String>) -> Self {
331 Self {
332 key: key.into(),
333 value: None,
334 children: Vec::new(),
335 }
336 }
337 pub fn add_child(&mut self, child: ConfigNode) {
339 self.children.push(child);
340 }
341 pub fn key(&self) -> &str {
343 &self.key
344 }
345 pub fn value(&self) -> Option<&str> {
347 self.value.as_deref()
348 }
349 pub fn num_children(&self) -> usize {
351 self.children.len()
352 }
353 pub fn lookup(&self, path: &str) -> Option<&str> {
355 let mut parts = path.splitn(2, '.');
356 let head = parts.next()?;
357 let tail = parts.next();
358 if head != self.key {
359 return None;
360 }
361 match tail {
362 None => self.value.as_deref(),
363 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
364 }
365 }
366 fn lookup_relative(&self, path: &str) -> Option<&str> {
367 let mut parts = path.splitn(2, '.');
368 let head = parts.next()?;
369 let tail = parts.next();
370 if head != self.key {
371 return None;
372 }
373 match tail {
374 None => self.value.as_deref(),
375 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
376 }
377 }
378}
379#[allow(dead_code)]
381pub struct PathBuf {
382 components: Vec<String>,
383}
384#[allow(dead_code)]
385impl PathBuf {
386 pub fn new() -> Self {
388 Self {
389 components: Vec::new(),
390 }
391 }
392 pub fn push(&mut self, comp: impl Into<String>) {
394 self.components.push(comp.into());
395 }
396 pub fn pop(&mut self) {
398 self.components.pop();
399 }
400 pub fn as_str(&self) -> String {
402 self.components.join("/")
403 }
404 pub fn depth(&self) -> usize {
406 self.components.len()
407 }
408 pub fn clear(&mut self) {
410 self.components.clear();
411 }
412}
413#[allow(dead_code)]
415pub struct WriteOnce<T> {
416 value: std::cell::Cell<Option<T>>,
417}
418#[allow(dead_code)]
419impl<T: Copy> WriteOnce<T> {
420 pub fn new() -> Self {
422 Self {
423 value: std::cell::Cell::new(None),
424 }
425 }
426 pub fn write(&self, val: T) -> bool {
428 if self.value.get().is_some() {
429 return false;
430 }
431 self.value.set(Some(val));
432 true
433 }
434 pub fn read(&self) -> Option<T> {
436 self.value.get()
437 }
438 pub fn is_written(&self) -> bool {
440 self.value.get().is_some()
441 }
442}
443#[allow(dead_code)]
445pub struct StackCalc {
446 stack: Vec<i64>,
447}
448#[allow(dead_code)]
449impl StackCalc {
450 pub fn new() -> Self {
452 Self { stack: Vec::new() }
453 }
454 pub fn push(&mut self, n: i64) {
456 self.stack.push(n);
457 }
458 pub fn add(&mut self) {
460 let b = self
461 .stack
462 .pop()
463 .expect("stack must have at least two values for add");
464 let a = self
465 .stack
466 .pop()
467 .expect("stack must have at least two values for add");
468 self.stack.push(a + b);
469 }
470 pub fn sub(&mut self) {
472 let b = self
473 .stack
474 .pop()
475 .expect("stack must have at least two values for sub");
476 let a = self
477 .stack
478 .pop()
479 .expect("stack must have at least two values for sub");
480 self.stack.push(a - b);
481 }
482 pub fn mul(&mut self) {
484 let b = self
485 .stack
486 .pop()
487 .expect("stack must have at least two values for mul");
488 let a = self
489 .stack
490 .pop()
491 .expect("stack must have at least two values for mul");
492 self.stack.push(a * b);
493 }
494 pub fn peek(&self) -> Option<i64> {
496 self.stack.last().copied()
497 }
498 pub fn depth(&self) -> usize {
500 self.stack.len()
501 }
502}
503#[allow(dead_code)]
505pub struct TransitiveClosure {
506 adj: Vec<Vec<usize>>,
507 n: usize,
508}
509#[allow(dead_code)]
510impl TransitiveClosure {
511 pub fn new(n: usize) -> Self {
513 Self {
514 adj: vec![Vec::new(); n],
515 n,
516 }
517 }
518 pub fn add_edge(&mut self, from: usize, to: usize) {
520 if from < self.n {
521 self.adj[from].push(to);
522 }
523 }
524 pub fn reachable_from(&self, start: usize) -> Vec<usize> {
526 let mut visited = vec![false; self.n];
527 let mut queue = std::collections::VecDeque::new();
528 queue.push_back(start);
529 while let Some(node) = queue.pop_front() {
530 if node >= self.n || visited[node] {
531 continue;
532 }
533 visited[node] = true;
534 for &next in &self.adj[node] {
535 queue.push_back(next);
536 }
537 }
538 (0..self.n).filter(|&i| visited[i]).collect()
539 }
540 pub fn can_reach(&self, from: usize, to: usize) -> bool {
542 self.reachable_from(from).contains(&to)
543 }
544}
545#[allow(dead_code)]
547pub enum Either2<A, B> {
548 First(A),
550 Second(B),
552}
553#[allow(dead_code)]
554impl<A, B> Either2<A, B> {
555 pub fn is_first(&self) -> bool {
557 matches!(self, Either2::First(_))
558 }
559 pub fn is_second(&self) -> bool {
561 matches!(self, Either2::Second(_))
562 }
563 pub fn first(self) -> Option<A> {
565 match self {
566 Either2::First(a) => Some(a),
567 _ => None,
568 }
569 }
570 pub fn second(self) -> Option<B> {
572 match self {
573 Either2::Second(b) => Some(b),
574 _ => None,
575 }
576 }
577 pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
579 match self {
580 Either2::First(a) => Either2::First(f(a)),
581 Either2::Second(b) => Either2::Second(b),
582 }
583 }
584}
585#[allow(dead_code)]
587pub struct RawFnPtr {
588 ptr: usize,
590 arity: usize,
591 name: String,
592}
593#[allow(dead_code)]
594impl RawFnPtr {
595 pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
597 Self {
598 ptr,
599 arity,
600 name: name.into(),
601 }
602 }
603 pub fn arity(&self) -> usize {
605 self.arity
606 }
607 pub fn name(&self) -> &str {
609 &self.name
610 }
611 pub fn raw(&self) -> usize {
613 self.ptr
614 }
615}
616#[allow(dead_code)]
618pub struct LabelSet {
619 labels: Vec<String>,
620}
621#[allow(dead_code)]
622impl LabelSet {
623 pub fn new() -> Self {
625 Self { labels: Vec::new() }
626 }
627 pub fn add(&mut self, label: impl Into<String>) {
629 let s = label.into();
630 if !self.labels.contains(&s) {
631 self.labels.push(s);
632 }
633 }
634 pub fn has(&self, label: &str) -> bool {
636 self.labels.iter().any(|l| l == label)
637 }
638 pub fn count(&self) -> usize {
640 self.labels.len()
641 }
642 pub fn all(&self) -> &[String] {
644 &self.labels
645 }
646}
647#[allow(dead_code)]
649pub struct StringPool {
650 free: Vec<String>,
651}
652#[allow(dead_code)]
653impl StringPool {
654 pub fn new() -> Self {
656 Self { free: Vec::new() }
657 }
658 pub fn take(&mut self) -> String {
660 self.free.pop().unwrap_or_default()
661 }
662 pub fn give(&mut self, mut s: String) {
664 s.clear();
665 self.free.push(s);
666 }
667 pub fn free_count(&self) -> usize {
669 self.free.len()
670 }
671}
672#[allow(dead_code)]
674pub struct SimpleDag {
675 edges: Vec<Vec<usize>>,
677}
678#[allow(dead_code)]
679impl SimpleDag {
680 pub fn new(n: usize) -> Self {
682 Self {
683 edges: vec![Vec::new(); n],
684 }
685 }
686 pub fn add_edge(&mut self, from: usize, to: usize) {
688 if from < self.edges.len() {
689 self.edges[from].push(to);
690 }
691 }
692 pub fn successors(&self, node: usize) -> &[usize] {
694 self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
695 }
696 pub fn can_reach(&self, from: usize, to: usize) -> bool {
698 let mut visited = vec![false; self.edges.len()];
699 self.dfs(from, to, &mut visited)
700 }
701 fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
702 if cur == target {
703 return true;
704 }
705 if cur >= visited.len() || visited[cur] {
706 return false;
707 }
708 visited[cur] = true;
709 for &next in self.successors(cur) {
710 if self.dfs(next, target, visited) {
711 return true;
712 }
713 }
714 false
715 }
716 pub fn topological_sort(&self) -> Option<Vec<usize>> {
718 let n = self.edges.len();
719 let mut in_degree = vec![0usize; n];
720 for succs in &self.edges {
721 for &s in succs {
722 if s < n {
723 in_degree[s] += 1;
724 }
725 }
726 }
727 let mut queue: std::collections::VecDeque<usize> =
728 (0..n).filter(|&i| in_degree[i] == 0).collect();
729 let mut order = Vec::new();
730 while let Some(node) = queue.pop_front() {
731 order.push(node);
732 for &s in self.successors(node) {
733 if s < n {
734 in_degree[s] -= 1;
735 if in_degree[s] == 0 {
736 queue.push_back(s);
737 }
738 }
739 }
740 }
741 if order.len() == n {
742 Some(order)
743 } else {
744 None
745 }
746 }
747 pub fn num_nodes(&self) -> usize {
749 self.edges.len()
750 }
751}
752#[allow(dead_code)]
754pub struct RewriteRuleSet {
755 rules: Vec<RewriteRule>,
756}
757#[allow(dead_code)]
758impl RewriteRuleSet {
759 pub fn new() -> Self {
761 Self { rules: Vec::new() }
762 }
763 pub fn add(&mut self, rule: RewriteRule) {
765 self.rules.push(rule);
766 }
767 pub fn len(&self) -> usize {
769 self.rules.len()
770 }
771 pub fn is_empty(&self) -> bool {
773 self.rules.is_empty()
774 }
775 pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
777 self.rules.iter().filter(|r| r.conditional).collect()
778 }
779 pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
781 self.rules.iter().filter(|r| !r.conditional).collect()
782 }
783 pub fn get(&self, name: &str) -> Option<&RewriteRule> {
785 self.rules.iter().find(|r| r.name == name)
786 }
787}
788#[derive(Clone, Copy, Debug, PartialEq, Eq)]
790pub enum NormStrategy {
791 None,
793 Whnf,
795 Full,
797 Bounded(usize),
799}
800#[allow(dead_code)]
802pub struct FlatSubstitution {
803 pairs: Vec<(String, String)>,
804}
805#[allow(dead_code)]
806impl FlatSubstitution {
807 pub fn new() -> Self {
809 Self { pairs: Vec::new() }
810 }
811 pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
813 self.pairs.push((from.into(), to.into()));
814 }
815 pub fn apply(&self, s: &str) -> String {
817 let mut result = s.to_string();
818 for (from, to) in &self.pairs {
819 result = result.replace(from.as_str(), to.as_str());
820 }
821 result
822 }
823 pub fn len(&self) -> usize {
825 self.pairs.len()
826 }
827 pub fn is_empty(&self) -> bool {
829 self.pairs.is_empty()
830 }
831}
832#[allow(dead_code)]
834pub struct VersionedRecord<T: Clone> {
835 history: Vec<T>,
836}
837#[allow(dead_code)]
838impl<T: Clone> VersionedRecord<T> {
839 pub fn new(initial: T) -> Self {
841 Self {
842 history: vec![initial],
843 }
844 }
845 pub fn update(&mut self, val: T) {
847 self.history.push(val);
848 }
849 pub fn current(&self) -> &T {
851 self.history
852 .last()
853 .expect("VersionedRecord history is always non-empty after construction")
854 }
855 pub fn at_version(&self, n: usize) -> Option<&T> {
857 self.history.get(n)
858 }
859 pub fn version(&self) -> usize {
861 self.history.len() - 1
862 }
863 pub fn has_history(&self) -> bool {
865 self.history.len() > 1
866 }
867}
868#[allow(dead_code)]
872pub struct MemoizedNormalizer {
873 pub(super) cache: HashMap<String, Expr>,
874}
875impl MemoizedNormalizer {
876 #[allow(dead_code)]
878 pub fn new() -> Self {
879 MemoizedNormalizer {
880 cache: HashMap::new(),
881 }
882 }
883 #[allow(dead_code)]
885 pub fn normalize(&mut self, expr: &Expr) -> Expr {
886 let key = format!("{:?}", expr);
887 if let Some(cached) = self.cache.get(&key) {
888 return cached.clone();
889 }
890 let result = normalize(expr);
891 self.cache.insert(key, result.clone());
892 result
893 }
894 #[allow(dead_code)]
896 pub fn clear_cache(&mut self) {
897 self.cache.clear();
898 }
899 #[allow(dead_code)]
901 pub fn cache_size(&self) -> usize {
902 self.cache.len()
903 }
904}
905#[allow(dead_code)]
907pub struct Fixture {
908 data: std::collections::HashMap<String, String>,
909}
910#[allow(dead_code)]
911impl Fixture {
912 pub fn new() -> Self {
914 Self {
915 data: std::collections::HashMap::new(),
916 }
917 }
918 pub fn set(&mut self, key: impl Into<String>, val: impl Into<String>) {
920 self.data.insert(key.into(), val.into());
921 }
922 pub fn get(&self, key: &str) -> Option<&str> {
924 self.data.get(key).map(|s| s.as_str())
925 }
926 pub fn len(&self) -> usize {
928 self.data.len()
929 }
930 pub fn is_empty(&self) -> bool {
932 self.len() == 0
933 }
934}
935#[allow(dead_code)]
937pub struct SlidingSum {
938 window: Vec<f64>,
939 capacity: usize,
940 pos: usize,
941 sum: f64,
942 count: usize,
943}
944#[allow(dead_code)]
945impl SlidingSum {
946 pub fn new(capacity: usize) -> Self {
948 Self {
949 window: vec![0.0; capacity],
950 capacity,
951 pos: 0,
952 sum: 0.0,
953 count: 0,
954 }
955 }
956 pub fn push(&mut self, val: f64) {
958 let oldest = self.window[self.pos];
959 self.sum -= oldest;
960 self.sum += val;
961 self.window[self.pos] = val;
962 self.pos = (self.pos + 1) % self.capacity;
963 if self.count < self.capacity {
964 self.count += 1;
965 }
966 }
967 pub fn sum(&self) -> f64 {
969 self.sum
970 }
971 pub fn mean(&self) -> Option<f64> {
973 if self.count == 0 {
974 None
975 } else {
976 Some(self.sum / self.count as f64)
977 }
978 }
979 pub fn count(&self) -> usize {
981 self.count
982 }
983}
984#[allow(dead_code)]
986pub struct NonEmptyVec<T> {
987 head: T,
988 tail: Vec<T>,
989}
990#[allow(dead_code)]
991impl<T> NonEmptyVec<T> {
992 pub fn singleton(val: T) -> Self {
994 Self {
995 head: val,
996 tail: Vec::new(),
997 }
998 }
999 pub fn push(&mut self, val: T) {
1001 self.tail.push(val);
1002 }
1003 pub fn first(&self) -> &T {
1005 &self.head
1006 }
1007 pub fn last(&self) -> &T {
1009 self.tail.last().unwrap_or(&self.head)
1010 }
1011 pub fn len(&self) -> usize {
1013 1 + self.tail.len()
1014 }
1015 pub fn is_empty(&self) -> bool {
1017 self.len() == 0
1018 }
1019 pub fn to_vec(&self) -> Vec<&T> {
1021 let mut v = vec![&self.head];
1022 v.extend(self.tail.iter());
1023 v
1024 }
1025}
1026#[allow(dead_code)]
1028pub struct PrefixCounter {
1029 children: std::collections::HashMap<char, PrefixCounter>,
1030 count: usize,
1031}
1032#[allow(dead_code)]
1033impl PrefixCounter {
1034 pub fn new() -> Self {
1036 Self {
1037 children: std::collections::HashMap::new(),
1038 count: 0,
1039 }
1040 }
1041 pub fn record(&mut self, s: &str) {
1043 self.count += 1;
1044 let mut node = self;
1045 for c in s.chars() {
1046 node = node.children.entry(c).or_default();
1047 node.count += 1;
1048 }
1049 }
1050 pub fn count_with_prefix(&self, prefix: &str) -> usize {
1052 let mut node = self;
1053 for c in prefix.chars() {
1054 match node.children.get(&c) {
1055 Some(n) => node = n,
1056 None => return 0,
1057 }
1058 }
1059 node.count
1060 }
1061}
1062pub struct LazyNormal {
1066 pub(super) original: Expr,
1067 pub(super) normal: std::cell::OnceCell<Expr>,
1068}
1069impl LazyNormal {
1070 pub fn new(e: Expr) -> Self {
1072 Self {
1073 original: e,
1074 normal: std::cell::OnceCell::new(),
1075 }
1076 }
1077 pub fn original(&self) -> &Expr {
1079 &self.original
1080 }
1081 pub fn normalized(&self) -> &Expr {
1083 self.normal.get_or_init(|| normalize(&self.original))
1084 }
1085 pub fn is_evaluated(&self) -> bool {
1087 self.normal.get().is_some()
1088 }
1089}
1090#[derive(Clone, Debug, Default)]
1092pub struct NormStats {
1093 pub visited: usize,
1095 pub cache_hits: usize,
1097 pub beta_steps: usize,
1099 pub let_steps: usize,
1101}
1102impl NormStats {
1103 pub fn new() -> Self {
1105 Self::default()
1106 }
1107 pub fn total_steps(&self) -> usize {
1109 self.beta_steps + self.let_steps
1110 }
1111}
1112#[allow(dead_code)]
1114pub struct TransformStat {
1115 before: StatSummary,
1116 after: StatSummary,
1117}
1118#[allow(dead_code)]
1119impl TransformStat {
1120 pub fn new() -> Self {
1122 Self {
1123 before: StatSummary::new(),
1124 after: StatSummary::new(),
1125 }
1126 }
1127 pub fn record_before(&mut self, v: f64) {
1129 self.before.record(v);
1130 }
1131 pub fn record_after(&mut self, v: f64) {
1133 self.after.record(v);
1134 }
1135 pub fn mean_ratio(&self) -> Option<f64> {
1137 let b = self.before.mean()?;
1138 let a = self.after.mean()?;
1139 if b.abs() < f64::EPSILON {
1140 return None;
1141 }
1142 Some(a / b)
1143 }
1144}
1145#[allow(dead_code)]
1147pub struct WindowIterator<'a, T> {
1148 pub(super) data: &'a [T],
1149 pub(super) pos: usize,
1150 pub(super) window: usize,
1151}
1152#[allow(dead_code)]
1153impl<'a, T> WindowIterator<'a, T> {
1154 pub fn new(data: &'a [T], window: usize) -> Self {
1156 Self {
1157 data,
1158 pos: 0,
1159 window,
1160 }
1161 }
1162}
1163#[allow(dead_code)]
1165pub struct MinHeap<T: Ord> {
1166 data: Vec<T>,
1167}
1168#[allow(dead_code)]
1169impl<T: Ord> MinHeap<T> {
1170 pub fn new() -> Self {
1172 Self { data: Vec::new() }
1173 }
1174 pub fn push(&mut self, val: T) {
1176 self.data.push(val);
1177 self.sift_up(self.data.len() - 1);
1178 }
1179 pub fn pop(&mut self) -> Option<T> {
1181 if self.data.is_empty() {
1182 return None;
1183 }
1184 let n = self.data.len();
1185 self.data.swap(0, n - 1);
1186 let min = self.data.pop();
1187 if !self.data.is_empty() {
1188 self.sift_down(0);
1189 }
1190 min
1191 }
1192 pub fn peek(&self) -> Option<&T> {
1194 self.data.first()
1195 }
1196 pub fn len(&self) -> usize {
1198 self.data.len()
1199 }
1200 pub fn is_empty(&self) -> bool {
1202 self.data.is_empty()
1203 }
1204 fn sift_up(&mut self, mut i: usize) {
1205 while i > 0 {
1206 let parent = (i - 1) / 2;
1207 if self.data[i] < self.data[parent] {
1208 self.data.swap(i, parent);
1209 i = parent;
1210 } else {
1211 break;
1212 }
1213 }
1214 }
1215 fn sift_down(&mut self, mut i: usize) {
1216 let n = self.data.len();
1217 loop {
1218 let left = 2 * i + 1;
1219 let right = 2 * i + 2;
1220 let mut smallest = i;
1221 if left < n && self.data[left] < self.data[smallest] {
1222 smallest = left;
1223 }
1224 if right < n && self.data[right] < self.data[smallest] {
1225 smallest = right;
1226 }
1227 if smallest == i {
1228 break;
1229 }
1230 self.data.swap(i, smallest);
1231 i = smallest;
1232 }
1233 }
1234}
1235#[allow(dead_code)]
1237#[allow(missing_docs)]
1238pub struct RewriteRule {
1239 pub name: String,
1241 pub lhs: String,
1243 pub rhs: String,
1245 pub conditional: bool,
1247}
1248#[allow(dead_code)]
1249impl RewriteRule {
1250 pub fn unconditional(
1252 name: impl Into<String>,
1253 lhs: impl Into<String>,
1254 rhs: impl Into<String>,
1255 ) -> Self {
1256 Self {
1257 name: name.into(),
1258 lhs: lhs.into(),
1259 rhs: rhs.into(),
1260 conditional: false,
1261 }
1262 }
1263 pub fn conditional(
1265 name: impl Into<String>,
1266 lhs: impl Into<String>,
1267 rhs: impl Into<String>,
1268 ) -> Self {
1269 Self {
1270 name: name.into(),
1271 lhs: lhs.into(),
1272 rhs: rhs.into(),
1273 conditional: true,
1274 }
1275 }
1276 pub fn display(&self) -> String {
1278 format!("{}: {} → {}", self.name, self.lhs, self.rhs)
1279 }
1280}