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: crate::wall_clock::Instant,
114 splits: Vec<f64>,
115}
116#[allow(dead_code)]
117impl Stopwatch {
118 pub fn start() -> Self {
120 Self {
121 start: crate::wall_clock::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: crate::wall_clock::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: crate::wall_clock::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 = crate::wall_clock::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 fn apply_binary(&mut self, op: impl FnOnce(i64, i64) -> i64) -> Option<i64> {
462 let (rest_len, a, b) = match self.stack[..] {
463 [ref rest @ .., a, b] => (rest.len(), a, b),
464 _ => return None,
465 };
466 let value = op(a, b);
467 self.stack.truncate(rest_len);
468 self.stack.push(value);
469 Some(value)
470 }
471 pub fn add(&mut self) -> Option<i64> {
475 self.apply_binary(|a, b| a + b)
476 }
477 pub fn sub(&mut self) -> Option<i64> {
481 self.apply_binary(|a, b| a - b)
482 }
483 pub fn mul(&mut self) -> Option<i64> {
487 self.apply_binary(|a, b| a * b)
488 }
489 pub fn peek(&self) -> Option<i64> {
491 self.stack.last().copied()
492 }
493 pub fn depth(&self) -> usize {
495 self.stack.len()
496 }
497}
498#[allow(dead_code)]
500pub struct TransitiveClosure {
501 adj: Vec<Vec<usize>>,
502 n: usize,
503}
504#[allow(dead_code)]
505impl TransitiveClosure {
506 pub fn new(n: usize) -> Self {
508 Self {
509 adj: vec![Vec::new(); n],
510 n,
511 }
512 }
513 pub fn add_edge(&mut self, from: usize, to: usize) {
515 if from < self.n {
516 self.adj[from].push(to);
517 }
518 }
519 pub fn reachable_from(&self, start: usize) -> Vec<usize> {
521 let mut visited = vec![false; self.n];
522 let mut queue = std::collections::VecDeque::new();
523 queue.push_back(start);
524 while let Some(node) = queue.pop_front() {
525 if node >= self.n || visited[node] {
526 continue;
527 }
528 visited[node] = true;
529 for &next in &self.adj[node] {
530 queue.push_back(next);
531 }
532 }
533 (0..self.n).filter(|&i| visited[i]).collect()
534 }
535 pub fn can_reach(&self, from: usize, to: usize) -> bool {
537 self.reachable_from(from).contains(&to)
538 }
539}
540#[allow(dead_code)]
542pub enum Either2<A, B> {
543 First(A),
545 Second(B),
547}
548#[allow(dead_code)]
549impl<A, B> Either2<A, B> {
550 pub fn is_first(&self) -> bool {
552 matches!(self, Either2::First(_))
553 }
554 pub fn is_second(&self) -> bool {
556 matches!(self, Either2::Second(_))
557 }
558 pub fn first(self) -> Option<A> {
560 match self {
561 Either2::First(a) => Some(a),
562 _ => None,
563 }
564 }
565 pub fn second(self) -> Option<B> {
567 match self {
568 Either2::Second(b) => Some(b),
569 _ => None,
570 }
571 }
572 pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
574 match self {
575 Either2::First(a) => Either2::First(f(a)),
576 Either2::Second(b) => Either2::Second(b),
577 }
578 }
579}
580#[allow(dead_code)]
582pub struct RawFnPtr {
583 ptr: usize,
585 arity: usize,
586 name: String,
587}
588#[allow(dead_code)]
589impl RawFnPtr {
590 pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
592 Self {
593 ptr,
594 arity,
595 name: name.into(),
596 }
597 }
598 pub fn arity(&self) -> usize {
600 self.arity
601 }
602 pub fn name(&self) -> &str {
604 &self.name
605 }
606 pub fn raw(&self) -> usize {
608 self.ptr
609 }
610}
611#[allow(dead_code)]
613pub struct LabelSet {
614 labels: Vec<String>,
615}
616#[allow(dead_code)]
617impl LabelSet {
618 pub fn new() -> Self {
620 Self { labels: Vec::new() }
621 }
622 pub fn add(&mut self, label: impl Into<String>) {
624 let s = label.into();
625 if !self.labels.contains(&s) {
626 self.labels.push(s);
627 }
628 }
629 pub fn has(&self, label: &str) -> bool {
631 self.labels.iter().any(|l| l == label)
632 }
633 pub fn count(&self) -> usize {
635 self.labels.len()
636 }
637 pub fn all(&self) -> &[String] {
639 &self.labels
640 }
641}
642#[allow(dead_code)]
644pub struct StringPool {
645 free: Vec<String>,
646}
647#[allow(dead_code)]
648impl StringPool {
649 pub fn new() -> Self {
651 Self { free: Vec::new() }
652 }
653 pub fn take(&mut self) -> String {
655 self.free.pop().unwrap_or_default()
656 }
657 pub fn give(&mut self, mut s: String) {
659 s.clear();
660 self.free.push(s);
661 }
662 pub fn free_count(&self) -> usize {
664 self.free.len()
665 }
666}
667#[allow(dead_code)]
669pub struct SimpleDag {
670 edges: Vec<Vec<usize>>,
672}
673#[allow(dead_code)]
674impl SimpleDag {
675 pub fn new(n: usize) -> Self {
677 Self {
678 edges: vec![Vec::new(); n],
679 }
680 }
681 pub fn add_edge(&mut self, from: usize, to: usize) {
683 if from < self.edges.len() {
684 self.edges[from].push(to);
685 }
686 }
687 pub fn successors(&self, node: usize) -> &[usize] {
689 self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
690 }
691 pub fn can_reach(&self, from: usize, to: usize) -> bool {
693 let mut visited = vec![false; self.edges.len()];
694 self.dfs(from, to, &mut visited)
695 }
696 fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
697 if cur == target {
698 return true;
699 }
700 if cur >= visited.len() || visited[cur] {
701 return false;
702 }
703 visited[cur] = true;
704 for &next in self.successors(cur) {
705 if self.dfs(next, target, visited) {
706 return true;
707 }
708 }
709 false
710 }
711 pub fn topological_sort(&self) -> Option<Vec<usize>> {
713 let n = self.edges.len();
714 let mut in_degree = vec![0usize; n];
715 for succs in &self.edges {
716 for &s in succs {
717 if s < n {
718 in_degree[s] += 1;
719 }
720 }
721 }
722 let mut queue: std::collections::VecDeque<usize> =
723 (0..n).filter(|&i| in_degree[i] == 0).collect();
724 let mut order = Vec::new();
725 while let Some(node) = queue.pop_front() {
726 order.push(node);
727 for &s in self.successors(node) {
728 if s < n {
729 in_degree[s] -= 1;
730 if in_degree[s] == 0 {
731 queue.push_back(s);
732 }
733 }
734 }
735 }
736 if order.len() == n {
737 Some(order)
738 } else {
739 None
740 }
741 }
742 pub fn num_nodes(&self) -> usize {
744 self.edges.len()
745 }
746}
747#[allow(dead_code)]
749pub struct RewriteRuleSet {
750 rules: Vec<RewriteRule>,
751}
752#[allow(dead_code)]
753impl RewriteRuleSet {
754 pub fn new() -> Self {
756 Self { rules: Vec::new() }
757 }
758 pub fn add(&mut self, rule: RewriteRule) {
760 self.rules.push(rule);
761 }
762 pub fn len(&self) -> usize {
764 self.rules.len()
765 }
766 pub fn is_empty(&self) -> bool {
768 self.rules.is_empty()
769 }
770 pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
772 self.rules.iter().filter(|r| r.conditional).collect()
773 }
774 pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
776 self.rules.iter().filter(|r| !r.conditional).collect()
777 }
778 pub fn get(&self, name: &str) -> Option<&RewriteRule> {
780 self.rules.iter().find(|r| r.name == name)
781 }
782}
783#[derive(Clone, Copy, Debug, PartialEq, Eq)]
785pub enum NormStrategy {
786 None,
788 Whnf,
790 Full,
792 Bounded(usize),
794}
795#[allow(dead_code)]
797pub struct FlatSubstitution {
798 pairs: Vec<(String, String)>,
799}
800#[allow(dead_code)]
801impl FlatSubstitution {
802 pub fn new() -> Self {
804 Self { pairs: Vec::new() }
805 }
806 pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
808 self.pairs.push((from.into(), to.into()));
809 }
810 pub fn apply(&self, s: &str) -> String {
812 let mut result = s.to_string();
813 for (from, to) in &self.pairs {
814 result = result.replace(from.as_str(), to.as_str());
815 }
816 result
817 }
818 pub fn len(&self) -> usize {
820 self.pairs.len()
821 }
822 pub fn is_empty(&self) -> bool {
824 self.pairs.is_empty()
825 }
826}
827#[allow(dead_code)]
829pub struct VersionedRecord<T: Clone> {
830 earlier: Vec<T>,
832 current: T,
834}
835#[allow(dead_code)]
836impl<T: Clone> VersionedRecord<T> {
837 pub fn new(initial: T) -> Self {
839 Self {
840 earlier: Vec::new(),
841 current: initial,
842 }
843 }
844 pub fn update(&mut self, val: T) {
846 let previous = std::mem::replace(&mut self.current, val);
847 self.earlier.push(previous);
848 }
849 pub fn current(&self) -> &T {
851 &self.current
852 }
853 pub fn at_version(&self, n: usize) -> Option<&T> {
855 match self.earlier.get(n) {
856 Some(value) => Some(value),
857 None if n == self.earlier.len() => Some(&self.current),
858 None => None,
859 }
860 }
861 pub fn version(&self) -> usize {
863 self.earlier.len()
864 }
865 pub fn has_history(&self) -> bool {
867 !self.earlier.is_empty()
868 }
869}
870#[allow(dead_code)]
874pub struct MemoizedNormalizer {
875 pub(super) cache: HashMap<String, Expr>,
876}
877impl MemoizedNormalizer {
878 #[allow(dead_code)]
880 pub fn new() -> Self {
881 MemoizedNormalizer {
882 cache: HashMap::new(),
883 }
884 }
885 #[allow(dead_code)]
887 pub fn normalize(&mut self, expr: &Expr) -> Expr {
888 let key = format!("{:?}", expr);
889 if let Some(cached) = self.cache.get(&key) {
890 return cached.clone();
891 }
892 let result = normalize(expr);
893 self.cache.insert(key, result.clone());
894 result
895 }
896 #[allow(dead_code)]
898 pub fn clear_cache(&mut self) {
899 self.cache.clear();
900 }
901 #[allow(dead_code)]
903 pub fn cache_size(&self) -> usize {
904 self.cache.len()
905 }
906}
907#[allow(dead_code)]
909pub struct Fixture {
910 data: std::collections::HashMap<String, String>,
911}
912#[allow(dead_code)]
913impl Fixture {
914 pub fn new() -> Self {
916 Self {
917 data: std::collections::HashMap::new(),
918 }
919 }
920 pub fn set(&mut self, key: impl Into<String>, val: impl Into<String>) {
922 self.data.insert(key.into(), val.into());
923 }
924 pub fn get(&self, key: &str) -> Option<&str> {
926 self.data.get(key).map(|s| s.as_str())
927 }
928 pub fn len(&self) -> usize {
930 self.data.len()
931 }
932 pub fn is_empty(&self) -> bool {
934 self.len() == 0
935 }
936}
937#[allow(dead_code)]
939pub struct SlidingSum {
940 window: Vec<f64>,
941 capacity: usize,
942 pos: usize,
943 sum: f64,
944 count: usize,
945}
946#[allow(dead_code)]
947impl SlidingSum {
948 pub fn new(capacity: usize) -> Self {
950 Self {
951 window: vec![0.0; capacity],
952 capacity,
953 pos: 0,
954 sum: 0.0,
955 count: 0,
956 }
957 }
958 pub fn push(&mut self, val: f64) {
960 let oldest = self.window[self.pos];
961 self.sum -= oldest;
962 self.sum += val;
963 self.window[self.pos] = val;
964 self.pos = (self.pos + 1) % self.capacity;
965 if self.count < self.capacity {
966 self.count += 1;
967 }
968 }
969 pub fn sum(&self) -> f64 {
971 self.sum
972 }
973 pub fn mean(&self) -> Option<f64> {
975 if self.count == 0 {
976 None
977 } else {
978 Some(self.sum / self.count as f64)
979 }
980 }
981 pub fn count(&self) -> usize {
983 self.count
984 }
985}
986#[allow(dead_code)]
988pub struct NonEmptyVec<T> {
989 head: T,
990 tail: Vec<T>,
991}
992#[allow(dead_code)]
993impl<T> NonEmptyVec<T> {
994 pub fn singleton(val: T) -> Self {
996 Self {
997 head: val,
998 tail: Vec::new(),
999 }
1000 }
1001 pub fn push(&mut self, val: T) {
1003 self.tail.push(val);
1004 }
1005 pub fn first(&self) -> &T {
1007 &self.head
1008 }
1009 pub fn last(&self) -> &T {
1011 self.tail.last().unwrap_or(&self.head)
1012 }
1013 pub fn len(&self) -> usize {
1015 1 + self.tail.len()
1016 }
1017 pub fn is_empty(&self) -> bool {
1019 self.len() == 0
1020 }
1021 pub fn to_vec(&self) -> Vec<&T> {
1023 let mut v = vec![&self.head];
1024 v.extend(self.tail.iter());
1025 v
1026 }
1027}
1028#[allow(dead_code)]
1030pub struct PrefixCounter {
1031 children: std::collections::HashMap<char, PrefixCounter>,
1032 count: usize,
1033}
1034#[allow(dead_code)]
1035impl PrefixCounter {
1036 pub fn new() -> Self {
1038 Self {
1039 children: std::collections::HashMap::new(),
1040 count: 0,
1041 }
1042 }
1043 pub fn record(&mut self, s: &str) {
1045 self.count += 1;
1046 let mut node = self;
1047 for c in s.chars() {
1048 node = node.children.entry(c).or_default();
1049 node.count += 1;
1050 }
1051 }
1052 pub fn count_with_prefix(&self, prefix: &str) -> usize {
1054 let mut node = self;
1055 for c in prefix.chars() {
1056 match node.children.get(&c) {
1057 Some(n) => node = n,
1058 None => return 0,
1059 }
1060 }
1061 node.count
1062 }
1063}
1064pub struct LazyNormal {
1068 pub(super) original: Expr,
1069 pub(super) normal: std::cell::OnceCell<Expr>,
1070}
1071impl LazyNormal {
1072 pub fn new(e: Expr) -> Self {
1074 Self {
1075 original: e,
1076 normal: std::cell::OnceCell::new(),
1077 }
1078 }
1079 pub fn original(&self) -> &Expr {
1081 &self.original
1082 }
1083 pub fn normalized(&self) -> &Expr {
1085 self.normal.get_or_init(|| normalize(&self.original))
1086 }
1087 pub fn is_evaluated(&self) -> bool {
1089 self.normal.get().is_some()
1090 }
1091}
1092#[derive(Clone, Debug, Default)]
1094pub struct NormStats {
1095 pub visited: usize,
1097 pub cache_hits: usize,
1099 pub beta_steps: usize,
1101 pub let_steps: usize,
1103}
1104impl NormStats {
1105 pub fn new() -> Self {
1107 Self::default()
1108 }
1109 pub fn total_steps(&self) -> usize {
1111 self.beta_steps + self.let_steps
1112 }
1113}
1114#[allow(dead_code)]
1116pub struct TransformStat {
1117 before: StatSummary,
1118 after: StatSummary,
1119}
1120#[allow(dead_code)]
1121impl TransformStat {
1122 pub fn new() -> Self {
1124 Self {
1125 before: StatSummary::new(),
1126 after: StatSummary::new(),
1127 }
1128 }
1129 pub fn record_before(&mut self, v: f64) {
1131 self.before.record(v);
1132 }
1133 pub fn record_after(&mut self, v: f64) {
1135 self.after.record(v);
1136 }
1137 pub fn mean_ratio(&self) -> Option<f64> {
1139 let b = self.before.mean()?;
1140 let a = self.after.mean()?;
1141 if b.abs() < f64::EPSILON {
1142 return None;
1143 }
1144 Some(a / b)
1145 }
1146}
1147#[allow(dead_code)]
1149pub struct WindowIterator<'a, T> {
1150 pub(super) data: &'a [T],
1151 pub(super) pos: usize,
1152 pub(super) window: usize,
1153}
1154#[allow(dead_code)]
1155impl<'a, T> WindowIterator<'a, T> {
1156 pub fn new(data: &'a [T], window: usize) -> Self {
1158 Self {
1159 data,
1160 pos: 0,
1161 window,
1162 }
1163 }
1164}
1165#[allow(dead_code)]
1167pub struct MinHeap<T: Ord> {
1168 data: Vec<T>,
1169}
1170#[allow(dead_code)]
1171impl<T: Ord> MinHeap<T> {
1172 pub fn new() -> Self {
1174 Self { data: Vec::new() }
1175 }
1176 pub fn push(&mut self, val: T) {
1178 self.data.push(val);
1179 self.sift_up(self.data.len() - 1);
1180 }
1181 pub fn pop(&mut self) -> Option<T> {
1183 if self.data.is_empty() {
1184 return None;
1185 }
1186 let n = self.data.len();
1187 self.data.swap(0, n - 1);
1188 let min = self.data.pop();
1189 if !self.data.is_empty() {
1190 self.sift_down(0);
1191 }
1192 min
1193 }
1194 pub fn peek(&self) -> Option<&T> {
1196 self.data.first()
1197 }
1198 pub fn len(&self) -> usize {
1200 self.data.len()
1201 }
1202 pub fn is_empty(&self) -> bool {
1204 self.data.is_empty()
1205 }
1206 fn sift_up(&mut self, mut i: usize) {
1207 while i > 0 {
1208 let parent = (i - 1) / 2;
1209 if self.data[i] < self.data[parent] {
1210 self.data.swap(i, parent);
1211 i = parent;
1212 } else {
1213 break;
1214 }
1215 }
1216 }
1217 fn sift_down(&mut self, mut i: usize) {
1218 let n = self.data.len();
1219 loop {
1220 let left = 2 * i + 1;
1221 let right = 2 * i + 2;
1222 let mut smallest = i;
1223 if left < n && self.data[left] < self.data[smallest] {
1224 smallest = left;
1225 }
1226 if right < n && self.data[right] < self.data[smallest] {
1227 smallest = right;
1228 }
1229 if smallest == i {
1230 break;
1231 }
1232 self.data.swap(i, smallest);
1233 i = smallest;
1234 }
1235 }
1236}
1237#[allow(dead_code)]
1239#[allow(missing_docs)]
1240pub struct RewriteRule {
1241 pub name: String,
1243 pub lhs: String,
1245 pub rhs: String,
1247 pub conditional: bool,
1249}
1250#[allow(dead_code)]
1251impl RewriteRule {
1252 pub fn unconditional(
1254 name: impl Into<String>,
1255 lhs: impl Into<String>,
1256 rhs: impl Into<String>,
1257 ) -> Self {
1258 Self {
1259 name: name.into(),
1260 lhs: lhs.into(),
1261 rhs: rhs.into(),
1262 conditional: false,
1263 }
1264 }
1265 pub fn conditional(
1267 name: impl Into<String>,
1268 lhs: impl Into<String>,
1269 rhs: impl Into<String>,
1270 ) -> Self {
1271 Self {
1272 name: name.into(),
1273 lhs: lhs.into(),
1274 rhs: rhs.into(),
1275 conditional: true,
1276 }
1277 }
1278 pub fn display(&self) -> String {
1280 format!("{}: {} → {}", self.name, self.lhs, self.rhs)
1281 }
1282}