1use crate::{BinderInfo, Expr, Level, Literal, Name};
6use std::collections::HashMap;
7use std::hash::{Hash, Hasher};
8
9#[allow(dead_code)]
11pub struct TransformStat {
12 before: StatSummary,
13 after: StatSummary,
14}
15#[allow(dead_code)]
16impl TransformStat {
17 pub fn new() -> Self {
19 Self {
20 before: StatSummary::new(),
21 after: StatSummary::new(),
22 }
23 }
24 pub fn record_before(&mut self, v: f64) {
26 self.before.record(v);
27 }
28 pub fn record_after(&mut self, v: f64) {
30 self.after.record(v);
31 }
32 pub fn mean_ratio(&self) -> Option<f64> {
34 let b = self.before.mean()?;
35 let a = self.after.mean()?;
36 if b.abs() < f64::EPSILON {
37 return None;
38 }
39 Some(a / b)
40 }
41}
42#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
47pub struct ExprId(pub(crate) u32);
48impl ExprId {
49 pub fn as_u32(&self) -> u32 {
51 self.0
52 }
53}
54pub struct ExprHashcons {
60 id_to_expr: Vec<Expr>,
62 expr_to_id: HashMap<ExprKey, ExprId>,
64 hit_count: u64,
66 miss_count: u64,
68}
69impl ExprHashcons {
70 pub fn new() -> Self {
72 ExprHashcons {
73 id_to_expr: Vec::new(),
74 expr_to_id: HashMap::new(),
75 hit_count: 0,
76 miss_count: 0,
77 }
78 }
79 pub fn intern(&mut self, expr: Expr) -> (ExprId, bool) {
84 let key = ExprKey(expr.clone());
85 if let Some(&id) = self.expr_to_id.get(&key) {
86 self.hit_count += 1;
87 (id, false)
88 } else {
89 let id = ExprId(self.id_to_expr.len() as u32);
90 self.id_to_expr.push(expr);
91 self.expr_to_id.insert(key, id);
92 self.miss_count += 1;
93 (id, true)
94 }
95 }
96 pub fn get(&self, id: ExprId) -> Option<&Expr> {
101 self.id_to_expr.get(id.0 as usize)
102 }
103 pub fn get_id(&self, expr: &Expr) -> Option<ExprId> {
107 let key = ExprKey(expr.clone());
108 self.expr_to_id.get(&key).copied()
109 }
110 pub fn size(&self) -> usize {
112 self.id_to_expr.len()
113 }
114 pub fn hit_rate(&self) -> f64 {
118 let total = self.hit_count + self.miss_count;
119 if total == 0 {
120 0.0
121 } else {
122 self.hit_count as f64 / total as f64
123 }
124 }
125 pub fn stats(&self) -> String {
127 format!(
128 "ExprHashcons {{ size: {}, hits: {}, misses: {}, hit_rate: {:.2}% }}",
129 self.size(),
130 self.hit_count,
131 self.miss_count,
132 self.hit_rate() * 100.0,
133 )
134 }
135}
136#[allow(dead_code)]
138pub enum Either2<A, B> {
139 First(A),
141 Second(B),
143}
144#[allow(dead_code)]
145impl<A, B> Either2<A, B> {
146 pub fn is_first(&self) -> bool {
148 matches!(self, Either2::First(_))
149 }
150 pub fn is_second(&self) -> bool {
152 matches!(self, Either2::Second(_))
153 }
154 pub fn first(self) -> Option<A> {
156 match self {
157 Either2::First(a) => Some(a),
158 _ => None,
159 }
160 }
161 pub fn second(self) -> Option<B> {
163 match self {
164 Either2::Second(b) => Some(b),
165 _ => None,
166 }
167 }
168 pub fn map_first<C, F: FnOnce(A) -> C>(self, f: F) -> Either2<C, B> {
170 match self {
171 Either2::First(a) => Either2::First(f(a)),
172 Either2::Second(b) => Either2::Second(b),
173 }
174 }
175}
176#[allow(dead_code)]
178pub struct BitSet64 {
179 bits: u64,
180}
181#[allow(dead_code)]
182impl BitSet64 {
183 pub const fn new() -> Self {
185 Self { bits: 0 }
186 }
187 pub fn insert(&mut self, i: u32) {
189 if i < 64 {
190 self.bits |= 1u64 << i;
191 }
192 }
193 pub fn remove(&mut self, i: u32) {
195 if i < 64 {
196 self.bits &= !(1u64 << i);
197 }
198 }
199 pub fn contains(&self, i: u32) -> bool {
201 i < 64 && (self.bits >> i) & 1 != 0
202 }
203 pub fn len(&self) -> u32 {
205 self.bits.count_ones()
206 }
207 pub fn is_empty(&self) -> bool {
209 self.bits == 0
210 }
211 pub fn union(self, other: BitSet64) -> BitSet64 {
213 BitSet64 {
214 bits: self.bits | other.bits,
215 }
216 }
217 pub fn intersect(self, other: BitSet64) -> BitSet64 {
219 BitSet64 {
220 bits: self.bits & other.bits,
221 }
222 }
223}
224#[allow(dead_code)]
226pub struct StringPool {
227 free: Vec<String>,
228}
229#[allow(dead_code)]
230impl StringPool {
231 pub fn new() -> Self {
233 Self { free: Vec::new() }
234 }
235 pub fn take(&mut self) -> String {
237 self.free.pop().unwrap_or_default()
238 }
239 pub fn give(&mut self, mut s: String) {
241 s.clear();
242 self.free.push(s);
243 }
244 pub fn free_count(&self) -> usize {
246 self.free.len()
247 }
248}
249#[allow(dead_code)]
251#[allow(missing_docs)]
252pub enum DecisionNode {
253 Leaf(String),
255 Branch {
257 key: String,
258 val: String,
259 yes_branch: Box<DecisionNode>,
260 no_branch: Box<DecisionNode>,
261 },
262}
263#[allow(dead_code)]
264impl DecisionNode {
265 pub fn evaluate(&self, ctx: &std::collections::HashMap<String, String>) -> &str {
267 match self {
268 DecisionNode::Leaf(action) => action.as_str(),
269 DecisionNode::Branch {
270 key,
271 val,
272 yes_branch,
273 no_branch,
274 } => {
275 let actual = ctx.get(key).map(|s| s.as_str()).unwrap_or("");
276 if actual == val.as_str() {
277 yes_branch.evaluate(ctx)
278 } else {
279 no_branch.evaluate(ctx)
280 }
281 }
282 }
283 }
284 pub fn depth(&self) -> usize {
286 match self {
287 DecisionNode::Leaf(_) => 0,
288 DecisionNode::Branch {
289 yes_branch,
290 no_branch,
291 ..
292 } => 1 + yes_branch.depth().max(no_branch.depth()),
293 }
294 }
295}
296#[allow(dead_code)]
298pub struct WindowIterator<'a, T> {
299 pub(super) data: &'a [T],
300 pub(super) pos: usize,
301 pub(super) window: usize,
302}
303#[allow(dead_code)]
304impl<'a, T> WindowIterator<'a, T> {
305 pub fn new(data: &'a [T], window: usize) -> Self {
307 Self {
308 data,
309 pos: 0,
310 window,
311 }
312 }
313}
314#[allow(dead_code)]
316pub struct TokenBucket {
317 capacity: u64,
318 tokens: u64,
319 refill_per_ms: u64,
320 last_refill: std::time::Instant,
321}
322#[allow(dead_code)]
323impl TokenBucket {
324 pub fn new(capacity: u64, refill_per_ms: u64) -> Self {
326 Self {
327 capacity,
328 tokens: capacity,
329 refill_per_ms,
330 last_refill: std::time::Instant::now(),
331 }
332 }
333 pub fn try_consume(&mut self, n: u64) -> bool {
335 self.refill();
336 if self.tokens >= n {
337 self.tokens -= n;
338 true
339 } else {
340 false
341 }
342 }
343 fn refill(&mut self) {
344 let now = std::time::Instant::now();
345 let elapsed_ms = now.duration_since(self.last_refill).as_millis() as u64;
346 if elapsed_ms > 0 {
347 let new_tokens = elapsed_ms * self.refill_per_ms;
348 self.tokens = (self.tokens + new_tokens).min(self.capacity);
349 self.last_refill = now;
350 }
351 }
352 pub fn available(&self) -> u64 {
354 self.tokens
355 }
356 pub fn capacity(&self) -> u64 {
358 self.capacity
359 }
360}
361#[allow(dead_code)]
363pub struct SmallMap<K: Ord + Clone, V: Clone> {
364 entries: Vec<(K, V)>,
365}
366#[allow(dead_code)]
367impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
368 pub fn new() -> Self {
370 Self {
371 entries: Vec::new(),
372 }
373 }
374 pub fn insert(&mut self, key: K, val: V) {
376 match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
377 Ok(i) => self.entries[i].1 = val,
378 Err(i) => self.entries.insert(i, (key, val)),
379 }
380 }
381 pub fn get(&self, key: &K) -> Option<&V> {
383 self.entries
384 .binary_search_by_key(&key, |(k, _)| k)
385 .ok()
386 .map(|i| &self.entries[i].1)
387 }
388 pub fn len(&self) -> usize {
390 self.entries.len()
391 }
392 pub fn is_empty(&self) -> bool {
394 self.entries.is_empty()
395 }
396 pub fn keys(&self) -> Vec<&K> {
398 self.entries.iter().map(|(k, _)| k).collect()
399 }
400 pub fn values(&self) -> Vec<&V> {
402 self.entries.iter().map(|(_, v)| v).collect()
403 }
404}
405#[allow(dead_code)]
407pub struct FocusStack<T> {
408 items: Vec<T>,
409}
410#[allow(dead_code)]
411impl<T> FocusStack<T> {
412 pub fn new() -> Self {
414 Self { items: Vec::new() }
415 }
416 pub fn focus(&mut self, item: T) {
418 self.items.push(item);
419 }
420 pub fn blur(&mut self) -> Option<T> {
422 self.items.pop()
423 }
424 pub fn current(&self) -> Option<&T> {
426 self.items.last()
427 }
428 pub fn depth(&self) -> usize {
430 self.items.len()
431 }
432 pub fn is_empty(&self) -> bool {
434 self.items.is_empty()
435 }
436}
437#[allow(dead_code)]
439pub struct LabelSet {
440 labels: Vec<String>,
441}
442#[allow(dead_code)]
443impl LabelSet {
444 pub fn new() -> Self {
446 Self { labels: Vec::new() }
447 }
448 pub fn add(&mut self, label: impl Into<String>) {
450 let s = label.into();
451 if !self.labels.contains(&s) {
452 self.labels.push(s);
453 }
454 }
455 pub fn has(&self, label: &str) -> bool {
457 self.labels.iter().any(|l| l == label)
458 }
459 pub fn count(&self) -> usize {
461 self.labels.len()
462 }
463 pub fn all(&self) -> &[String] {
465 &self.labels
466 }
467}
468#[allow(dead_code)]
470#[allow(missing_docs)]
471pub struct RewriteRule {
472 pub name: String,
474 pub lhs: String,
476 pub rhs: String,
478 pub conditional: bool,
480}
481#[allow(dead_code)]
482impl RewriteRule {
483 pub fn unconditional(
485 name: impl Into<String>,
486 lhs: impl Into<String>,
487 rhs: impl Into<String>,
488 ) -> Self {
489 Self {
490 name: name.into(),
491 lhs: lhs.into(),
492 rhs: rhs.into(),
493 conditional: false,
494 }
495 }
496 pub fn conditional(
498 name: impl Into<String>,
499 lhs: impl Into<String>,
500 rhs: impl Into<String>,
501 ) -> Self {
502 Self {
503 name: name.into(),
504 lhs: lhs.into(),
505 rhs: rhs.into(),
506 conditional: true,
507 }
508 }
509 pub fn display(&self) -> String {
511 format!("{}: {} → {}", self.name, self.lhs, self.rhs)
512 }
513}
514#[allow(dead_code)]
516pub struct SimpleDag {
517 edges: Vec<Vec<usize>>,
519}
520#[allow(dead_code)]
521impl SimpleDag {
522 pub fn new(n: usize) -> Self {
524 Self {
525 edges: vec![Vec::new(); n],
526 }
527 }
528 pub fn add_edge(&mut self, from: usize, to: usize) {
530 if from < self.edges.len() {
531 self.edges[from].push(to);
532 }
533 }
534 pub fn successors(&self, node: usize) -> &[usize] {
536 self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
537 }
538 pub fn can_reach(&self, from: usize, to: usize) -> bool {
540 let mut visited = vec![false; self.edges.len()];
541 self.dfs(from, to, &mut visited)
542 }
543 fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
544 if cur == target {
545 return true;
546 }
547 if cur >= visited.len() || visited[cur] {
548 return false;
549 }
550 visited[cur] = true;
551 for &next in self.successors(cur) {
552 if self.dfs(next, target, visited) {
553 return true;
554 }
555 }
556 false
557 }
558 pub fn topological_sort(&self) -> Option<Vec<usize>> {
560 let n = self.edges.len();
561 let mut in_degree = vec![0usize; n];
562 for succs in &self.edges {
563 for &s in succs {
564 if s < n {
565 in_degree[s] += 1;
566 }
567 }
568 }
569 let mut queue: std::collections::VecDeque<usize> =
570 (0..n).filter(|&i| in_degree[i] == 0).collect();
571 let mut order = Vec::new();
572 while let Some(node) = queue.pop_front() {
573 order.push(node);
574 for &s in self.successors(node) {
575 if s < n {
576 in_degree[s] -= 1;
577 if in_degree[s] == 0 {
578 queue.push_back(s);
579 }
580 }
581 }
582 }
583 if order.len() == n {
584 Some(order)
585 } else {
586 None
587 }
588 }
589 pub fn num_nodes(&self) -> usize {
591 self.edges.len()
592 }
593}
594#[allow(dead_code)]
596pub struct RawFnPtr {
597 ptr: usize,
599 arity: usize,
600 name: String,
601}
602#[allow(dead_code)]
603impl RawFnPtr {
604 pub fn new(ptr: usize, arity: usize, name: impl Into<String>) -> Self {
606 Self {
607 ptr,
608 arity,
609 name: name.into(),
610 }
611 }
612 pub fn arity(&self) -> usize {
614 self.arity
615 }
616 pub fn name(&self) -> &str {
618 &self.name
619 }
620 pub fn raw(&self) -> usize {
622 self.ptr
623 }
624}
625#[allow(dead_code)]
627#[derive(Debug, Clone, Default)]
628pub struct CacheSessionStats {
629 pub hits: u64,
630 pub misses: u64,
631 pub insertions: u64,
632 pub evictions: u64,
633}
634#[allow(dead_code)]
635impl CacheSessionStats {
636 pub fn new() -> Self {
638 CacheSessionStats::default()
639 }
640 pub fn hit_rate(&self) -> f64 {
642 let total = self.hits + self.misses;
643 if total == 0 {
644 1.0
645 } else {
646 self.hits as f64 / total as f64
647 }
648 }
649 pub fn merge(&mut self, other: &CacheSessionStats) {
651 self.hits += other.hits;
652 self.misses += other.misses;
653 self.insertions += other.insertions;
654 self.evictions += other.evictions;
655 }
656 pub fn reset(&mut self) {
658 *self = CacheSessionStats::default();
659 }
660 pub fn summary(&self) -> String {
662 format!(
663 "hits={} misses={} insertions={} evictions={} hit_rate={:.1}%",
664 self.hits,
665 self.misses,
666 self.insertions,
667 self.evictions,
668 self.hit_rate() * 100.0
669 )
670 }
671}
672#[allow(dead_code)]
674pub struct NonEmptyVec<T> {
675 head: T,
676 tail: Vec<T>,
677}
678#[allow(dead_code)]
679impl<T> NonEmptyVec<T> {
680 pub fn singleton(val: T) -> Self {
682 Self {
683 head: val,
684 tail: Vec::new(),
685 }
686 }
687 pub fn push(&mut self, val: T) {
689 self.tail.push(val);
690 }
691 pub fn first(&self) -> &T {
693 &self.head
694 }
695 pub fn last(&self) -> &T {
697 self.tail.last().unwrap_or(&self.head)
698 }
699 pub fn len(&self) -> usize {
701 1 + self.tail.len()
702 }
703 pub fn is_empty(&self) -> bool {
705 self.len() == 0
706 }
707 pub fn to_vec(&self) -> Vec<&T> {
709 let mut v = vec![&self.head];
710 v.extend(self.tail.iter());
711 v
712 }
713}
714#[allow(dead_code)]
716pub struct MinHeap<T: Ord> {
717 data: Vec<T>,
718}
719#[allow(dead_code)]
720impl<T: Ord> MinHeap<T> {
721 pub fn new() -> Self {
723 Self { data: Vec::new() }
724 }
725 pub fn push(&mut self, val: T) {
727 self.data.push(val);
728 self.sift_up(self.data.len() - 1);
729 }
730 pub fn pop(&mut self) -> Option<T> {
732 if self.data.is_empty() {
733 return None;
734 }
735 let n = self.data.len();
736 self.data.swap(0, n - 1);
737 let min = self.data.pop();
738 if !self.data.is_empty() {
739 self.sift_down(0);
740 }
741 min
742 }
743 pub fn peek(&self) -> Option<&T> {
745 self.data.first()
746 }
747 pub fn len(&self) -> usize {
749 self.data.len()
750 }
751 pub fn is_empty(&self) -> bool {
753 self.data.is_empty()
754 }
755 fn sift_up(&mut self, mut i: usize) {
756 while i > 0 {
757 let parent = (i - 1) / 2;
758 if self.data[i] < self.data[parent] {
759 self.data.swap(i, parent);
760 i = parent;
761 } else {
762 break;
763 }
764 }
765 }
766 fn sift_down(&mut self, mut i: usize) {
767 let n = self.data.len();
768 loop {
769 let left = 2 * i + 1;
770 let right = 2 * i + 2;
771 let mut smallest = i;
772 if left < n && self.data[left] < self.data[smallest] {
773 smallest = left;
774 }
775 if right < n && self.data[right] < self.data[smallest] {
776 smallest = right;
777 }
778 if smallest == i {
779 break;
780 }
781 self.data.swap(i, smallest);
782 i = smallest;
783 }
784 }
785}
786#[allow(dead_code)]
788pub struct PrefixCounter {
789 children: std::collections::HashMap<char, PrefixCounter>,
790 count: usize,
791}
792#[allow(dead_code)]
793impl PrefixCounter {
794 pub fn new() -> Self {
796 Self {
797 children: std::collections::HashMap::new(),
798 count: 0,
799 }
800 }
801 pub fn record(&mut self, s: &str) {
803 self.count += 1;
804 let mut node = self;
805 for c in s.chars() {
806 node = node.children.entry(c).or_default();
807 node.count += 1;
808 }
809 }
810 pub fn count_with_prefix(&self, prefix: &str) -> usize {
812 let mut node = self;
813 for c in prefix.chars() {
814 match node.children.get(&c) {
815 Some(n) => node = n,
816 None => return 0,
817 }
818 }
819 node.count
820 }
821}
822#[allow(dead_code)]
824pub struct TwoLevelCache {
825 hot: MemoTable,
826 cold: MemoTable,
827 hot_capacity: usize,
828 stats: CacheSessionStats,
829}
830#[allow(dead_code)]
831impl TwoLevelCache {
832 pub fn new(hot_capacity: usize) -> Self {
834 TwoLevelCache {
835 hot: MemoTable::new(),
836 cold: MemoTable::new(),
837 hot_capacity,
838 stats: CacheSessionStats::new(),
839 }
840 }
841 pub fn get(&mut self, key: u64) -> Option<u64> {
843 if let Some(v) = self.hot.get(key) {
844 self.stats.hits += 1;
845 return Some(v);
846 }
847 if let Some(v) = self.cold.get(key) {
848 self.stats.hits += 1;
849 self.promote(key, v);
850 return Some(v);
851 }
852 self.stats.misses += 1;
853 None
854 }
855 pub fn insert(&mut self, key: u64, val: u64) {
857 if self.hot.len() >= self.hot_capacity {
858 if let Some((k, v)) = self.hot.entries.first().copied() {
859 self.hot.remove(k);
860 self.cold.insert(k, v);
861 self.stats.evictions += 1;
862 }
863 }
864 self.hot.insert(key, val);
865 self.stats.insertions += 1;
866 }
867 fn promote(&mut self, key: u64, val: u64) {
868 self.cold.remove(key);
869 self.insert(key, val);
870 }
871 pub fn stats(&self) -> &CacheSessionStats {
873 &self.stats
874 }
875 pub fn total_len(&self) -> usize {
877 self.hot.len() + self.cold.len()
878 }
879 pub fn clear(&mut self) {
881 self.hot.clear();
882 self.cold.clear();
883 self.stats.reset();
884 }
885}
886#[allow(dead_code)]
888pub struct TransitiveClosure {
889 adj: Vec<Vec<usize>>,
890 n: usize,
891}
892#[allow(dead_code)]
893impl TransitiveClosure {
894 pub fn new(n: usize) -> Self {
896 Self {
897 adj: vec![Vec::new(); n],
898 n,
899 }
900 }
901 pub fn add_edge(&mut self, from: usize, to: usize) {
903 if from < self.n {
904 self.adj[from].push(to);
905 }
906 }
907 pub fn reachable_from(&self, start: usize) -> Vec<usize> {
909 let mut visited = vec![false; self.n];
910 let mut queue = std::collections::VecDeque::new();
911 queue.push_back(start);
912 while let Some(node) = queue.pop_front() {
913 if node >= self.n || visited[node] {
914 continue;
915 }
916 visited[node] = true;
917 for &next in &self.adj[node] {
918 queue.push_back(next);
919 }
920 }
921 (0..self.n).filter(|&i| visited[i]).collect()
922 }
923 pub fn can_reach(&self, from: usize, to: usize) -> bool {
925 self.reachable_from(from).contains(&to)
926 }
927}
928#[allow(dead_code)]
929struct PathNode {
930 key: u32,
931 value: Option<u64>,
932 children: Vec<usize>,
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 Fixture {
979 data: std::collections::HashMap<String, String>,
980}
981#[allow(dead_code)]
982impl Fixture {
983 pub fn new() -> Self {
985 Self {
986 data: std::collections::HashMap::new(),
987 }
988 }
989 pub fn set(&mut self, key: impl Into<String>, val: impl Into<String>) {
991 self.data.insert(key.into(), val.into());
992 }
993 pub fn get(&self, key: &str) -> Option<&str> {
995 self.data.get(key).map(|s| s.as_str())
996 }
997 pub fn len(&self) -> usize {
999 self.data.len()
1000 }
1001 pub fn is_empty(&self) -> bool {
1003 self.len() == 0
1004 }
1005}
1006#[allow(dead_code)]
1008pub struct VersionedRecord<T: Clone> {
1009 history: Vec<T>,
1010}
1011#[allow(dead_code)]
1012impl<T: Clone> VersionedRecord<T> {
1013 pub fn new(initial: T) -> Self {
1015 Self {
1016 history: vec![initial],
1017 }
1018 }
1019 pub fn update(&mut self, val: T) {
1021 self.history.push(val);
1022 }
1023 pub fn current(&self) -> &T {
1025 self.history
1026 .last()
1027 .expect("VersionedRecord history is always non-empty after construction")
1028 }
1029 pub fn at_version(&self, n: usize) -> Option<&T> {
1031 self.history.get(n)
1032 }
1033 pub fn version(&self) -> usize {
1035 self.history.len() - 1
1036 }
1037 pub fn has_history(&self) -> bool {
1039 self.history.len() > 1
1040 }
1041}
1042#[allow(dead_code)]
1044pub struct InvalidationSet {
1045 ids: Vec<u64>,
1046}
1047#[allow(dead_code)]
1048impl InvalidationSet {
1049 pub fn new() -> Self {
1051 InvalidationSet { ids: Vec::new() }
1052 }
1053 pub fn add(&mut self, id: u64) {
1055 if !self.ids.contains(&id) {
1056 self.ids.push(id);
1057 }
1058 }
1059 pub fn contains(&self, id: u64) -> bool {
1061 self.ids.contains(&id)
1062 }
1063 pub fn ids(&self) -> &[u64] {
1065 &self.ids
1066 }
1067 pub fn clear(&mut self) {
1069 self.ids.clear();
1070 }
1071 pub fn len(&self) -> usize {
1073 self.ids.len()
1074 }
1075 pub fn is_empty(&self) -> bool {
1077 self.ids.is_empty()
1078 }
1079}
1080#[allow(dead_code)]
1082pub struct RcExprPool {
1083 entries: Vec<SharedCacheEntry>,
1084}
1085#[allow(dead_code)]
1086impl RcExprPool {
1087 pub fn new() -> Self {
1089 RcExprPool {
1090 entries: Vec::new(),
1091 }
1092 }
1093 pub fn alloc(&mut self, hash: u64) -> usize {
1095 let id = self.entries.len() as u64;
1096 self.entries.push(SharedCacheEntry::new(id, hash));
1097 self.entries.len() - 1
1098 }
1099 pub fn inc_ref(&mut self, idx: usize) {
1101 if let Some(e) = self.entries.get_mut(idx) {
1102 e.inc_ref();
1103 }
1104 }
1105 pub fn dec_ref(&mut self, idx: usize) -> bool {
1107 if let Some(e) = self.entries.get_mut(idx) {
1108 e.dec_ref()
1109 } else {
1110 false
1111 }
1112 }
1113 pub fn collect_garbage(&mut self) -> Vec<usize> {
1115 self.entries
1116 .iter()
1117 .enumerate()
1118 .filter(|(_, e)| e.is_dead())
1119 .map(|(i, _)| i)
1120 .collect()
1121 }
1122 pub fn len(&self) -> usize {
1124 self.entries.len()
1125 }
1126 pub fn is_empty(&self) -> bool {
1128 self.entries.is_empty()
1129 }
1130 pub fn live_count(&self) -> usize {
1132 self.entries.iter().filter(|e| !e.is_dead()).count()
1133 }
1134}
1135#[allow(dead_code)]
1137pub struct EvictionTracker {
1138 capacity: usize,
1139 order: Vec<u64>,
1140}
1141#[allow(dead_code)]
1142impl EvictionTracker {
1143 pub fn new(capacity: usize) -> Self {
1145 EvictionTracker {
1146 capacity,
1147 order: Vec::with_capacity(capacity),
1148 }
1149 }
1150 pub fn access(&mut self, id: u64) {
1152 if let Some(pos) = self.order.iter().position(|&x| x == id) {
1153 self.order.remove(pos);
1154 }
1155 self.order.push(id);
1156 while self.order.len() > self.capacity {
1157 self.order.remove(0);
1158 }
1159 }
1160 pub fn lru(&self) -> Option<u64> {
1162 self.order.first().copied()
1163 }
1164 pub fn mru(&self) -> Option<u64> {
1166 self.order.last().copied()
1167 }
1168 pub fn len(&self) -> usize {
1170 self.order.len()
1171 }
1172 pub fn is_empty(&self) -> bool {
1174 self.order.is_empty()
1175 }
1176 pub fn evict_lru(&mut self) -> Option<u64> {
1178 if self.order.is_empty() {
1179 None
1180 } else {
1181 Some(self.order.remove(0))
1182 }
1183 }
1184}
1185#[allow(dead_code)]
1187pub struct StatSummary {
1188 count: u64,
1189 sum: f64,
1190 min: f64,
1191 max: f64,
1192}
1193#[allow(dead_code)]
1194impl StatSummary {
1195 pub fn new() -> Self {
1197 Self {
1198 count: 0,
1199 sum: 0.0,
1200 min: f64::INFINITY,
1201 max: f64::NEG_INFINITY,
1202 }
1203 }
1204 pub fn record(&mut self, val: f64) {
1206 self.count += 1;
1207 self.sum += val;
1208 if val < self.min {
1209 self.min = val;
1210 }
1211 if val > self.max {
1212 self.max = val;
1213 }
1214 }
1215 pub fn mean(&self) -> Option<f64> {
1217 if self.count == 0 {
1218 None
1219 } else {
1220 Some(self.sum / self.count as f64)
1221 }
1222 }
1223 pub fn min(&self) -> Option<f64> {
1225 if self.count == 0 {
1226 None
1227 } else {
1228 Some(self.min)
1229 }
1230 }
1231 pub fn max(&self) -> Option<f64> {
1233 if self.count == 0 {
1234 None
1235 } else {
1236 Some(self.max)
1237 }
1238 }
1239 pub fn count(&self) -> u64 {
1241 self.count
1242 }
1243}
1244#[allow(dead_code)]
1246pub struct ConfigNode {
1247 key: String,
1248 value: Option<String>,
1249 children: Vec<ConfigNode>,
1250}
1251#[allow(dead_code)]
1252impl ConfigNode {
1253 pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
1255 Self {
1256 key: key.into(),
1257 value: Some(value.into()),
1258 children: Vec::new(),
1259 }
1260 }
1261 pub fn section(key: impl Into<String>) -> Self {
1263 Self {
1264 key: key.into(),
1265 value: None,
1266 children: Vec::new(),
1267 }
1268 }
1269 pub fn add_child(&mut self, child: ConfigNode) {
1271 self.children.push(child);
1272 }
1273 pub fn key(&self) -> &str {
1275 &self.key
1276 }
1277 pub fn value(&self) -> Option<&str> {
1279 self.value.as_deref()
1280 }
1281 pub fn num_children(&self) -> usize {
1283 self.children.len()
1284 }
1285 pub fn lookup(&self, path: &str) -> Option<&str> {
1287 let mut parts = path.splitn(2, '.');
1288 let head = parts.next()?;
1289 let tail = parts.next();
1290 if head != self.key {
1291 return None;
1292 }
1293 match tail {
1294 None => self.value.as_deref(),
1295 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
1296 }
1297 }
1298 fn lookup_relative(&self, path: &str) -> Option<&str> {
1299 let mut parts = path.splitn(2, '.');
1300 let head = parts.next()?;
1301 let tail = parts.next();
1302 if head != self.key {
1303 return None;
1304 }
1305 match tail {
1306 None => self.value.as_deref(),
1307 Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
1308 }
1309 }
1310}
1311#[allow(dead_code)]
1313pub struct RewriteRuleSet {
1314 rules: Vec<RewriteRule>,
1315}
1316#[allow(dead_code)]
1317impl RewriteRuleSet {
1318 pub fn new() -> Self {
1320 Self { rules: Vec::new() }
1321 }
1322 pub fn add(&mut self, rule: RewriteRule) {
1324 self.rules.push(rule);
1325 }
1326 pub fn len(&self) -> usize {
1328 self.rules.len()
1329 }
1330 pub fn is_empty(&self) -> bool {
1332 self.rules.is_empty()
1333 }
1334 pub fn conditional_rules(&self) -> Vec<&RewriteRule> {
1336 self.rules.iter().filter(|r| r.conditional).collect()
1337 }
1338 pub fn unconditional_rules(&self) -> Vec<&RewriteRule> {
1340 self.rules.iter().filter(|r| !r.conditional).collect()
1341 }
1342 pub fn get(&self, name: &str) -> Option<&RewriteRule> {
1344 self.rules.iter().find(|r| r.name == name)
1345 }
1346}
1347#[allow(dead_code)]
1349pub struct StackCalc {
1350 stack: Vec<i64>,
1351}
1352#[allow(dead_code)]
1353impl StackCalc {
1354 pub fn new() -> Self {
1356 Self { stack: Vec::new() }
1357 }
1358 pub fn push(&mut self, n: i64) {
1360 self.stack.push(n);
1361 }
1362 pub fn add(&mut self) {
1364 let b = self
1365 .stack
1366 .pop()
1367 .expect("stack must have at least two values for add");
1368 let a = self
1369 .stack
1370 .pop()
1371 .expect("stack must have at least two values for add");
1372 self.stack.push(a + b);
1373 }
1374 pub fn sub(&mut self) {
1376 let b = self
1377 .stack
1378 .pop()
1379 .expect("stack must have at least two values for sub");
1380 let a = self
1381 .stack
1382 .pop()
1383 .expect("stack must have at least two values for sub");
1384 self.stack.push(a - b);
1385 }
1386 pub fn mul(&mut self) {
1388 let b = self
1389 .stack
1390 .pop()
1391 .expect("stack must have at least two values for mul");
1392 let a = self
1393 .stack
1394 .pop()
1395 .expect("stack must have at least two values for mul");
1396 self.stack.push(a * b);
1397 }
1398 pub fn peek(&self) -> Option<i64> {
1400 self.stack.last().copied()
1401 }
1402 pub fn depth(&self) -> usize {
1404 self.stack.len()
1405 }
1406}
1407#[allow(dead_code)]
1409pub struct VersionedCache {
1410 entries: Vec<(u64, u64, u64)>,
1411 current_version: u64,
1412}
1413#[allow(dead_code)]
1414impl VersionedCache {
1415 pub fn new() -> Self {
1417 VersionedCache {
1418 entries: Vec::new(),
1419 current_version: 0,
1420 }
1421 }
1422 pub fn bump_version(&mut self) {
1424 self.current_version += 1;
1425 }
1426 pub fn insert(&mut self, key: u64, val: u64) {
1428 let ver = self.current_version;
1429 if let Some(e) = self.entries.iter_mut().find(|(k, _, _)| *k == key) {
1430 e.1 = val;
1431 e.2 = ver;
1432 } else {
1433 self.entries.push((key, val, ver));
1434 }
1435 }
1436 pub fn get(&self, key: u64) -> Option<u64> {
1438 self.entries
1439 .iter()
1440 .find(|(k, _, v)| *k == key && *v == self.current_version)
1441 .map(|(_, val, _)| *val)
1442 }
1443 pub fn version(&self) -> u64 {
1445 self.current_version
1446 }
1447 pub fn evict_stale(&mut self) {
1449 let cur = self.current_version;
1450 self.entries.retain(|(_, _, v)| *v == cur);
1451 }
1452 pub fn valid_count(&self) -> usize {
1454 let cur = self.current_version;
1455 self.entries.iter().filter(|(_, _, v)| *v == cur).count()
1456 }
1457}
1458#[allow(dead_code)]
1460pub struct SlidingSum {
1461 window: Vec<f64>,
1462 capacity: usize,
1463 pos: usize,
1464 sum: f64,
1465 count: usize,
1466}
1467#[allow(dead_code)]
1468impl SlidingSum {
1469 pub fn new(capacity: usize) -> Self {
1471 Self {
1472 window: vec![0.0; capacity],
1473 capacity,
1474 pos: 0,
1475 sum: 0.0,
1476 count: 0,
1477 }
1478 }
1479 pub fn push(&mut self, val: f64) {
1481 let oldest = self.window[self.pos];
1482 self.sum -= oldest;
1483 self.sum += val;
1484 self.window[self.pos] = val;
1485 self.pos = (self.pos + 1) % self.capacity;
1486 if self.count < self.capacity {
1487 self.count += 1;
1488 }
1489 }
1490 pub fn sum(&self) -> f64 {
1492 self.sum
1493 }
1494 pub fn mean(&self) -> Option<f64> {
1496 if self.count == 0 {
1497 None
1498 } else {
1499 Some(self.sum / self.count as f64)
1500 }
1501 }
1502 pub fn count(&self) -> usize {
1504 self.count
1505 }
1506}
1507#[allow(dead_code)]
1509pub struct BucketCounter<const N: usize> {
1510 buckets: [u64; N],
1511}
1512#[allow(dead_code)]
1513impl<const N: usize> BucketCounter<N> {
1514 pub const fn new() -> Self {
1516 Self { buckets: [0u64; N] }
1517 }
1518 pub fn inc(&mut self, i: usize) {
1520 if i < N {
1521 self.buckets[i] += 1;
1522 }
1523 }
1524 pub fn get(&self, i: usize) -> u64 {
1526 if i < N {
1527 self.buckets[i]
1528 } else {
1529 0
1530 }
1531 }
1532 pub fn total(&self) -> u64 {
1534 self.buckets.iter().sum()
1535 }
1536 pub fn argmax(&self) -> usize {
1538 self.buckets
1539 .iter()
1540 .enumerate()
1541 .max_by_key(|(_, &v)| v)
1542 .map(|(i, _)| i)
1543 .unwrap_or(0)
1544 }
1545}
1546#[allow(dead_code)]
1548pub struct FlatSubstitution {
1549 pairs: Vec<(String, String)>,
1550}
1551#[allow(dead_code)]
1552impl FlatSubstitution {
1553 pub fn new() -> Self {
1555 Self { pairs: Vec::new() }
1556 }
1557 pub fn add(&mut self, from: impl Into<String>, to: impl Into<String>) {
1559 self.pairs.push((from.into(), to.into()));
1560 }
1561 pub fn apply(&self, s: &str) -> String {
1563 let mut result = s.to_string();
1564 for (from, to) in &self.pairs {
1565 result = result.replace(from.as_str(), to.as_str());
1566 }
1567 result
1568 }
1569 pub fn len(&self) -> usize {
1571 self.pairs.len()
1572 }
1573 pub fn is_empty(&self) -> bool {
1575 self.pairs.is_empty()
1576 }
1577}
1578#[allow(dead_code)]
1580pub struct PathCache {
1581 nodes: Vec<PathNode>,
1582}
1583#[allow(dead_code)]
1584impl PathCache {
1585 pub fn new() -> Self {
1587 PathCache {
1588 nodes: vec![PathNode {
1589 key: 0,
1590 value: None,
1591 children: Vec::new(),
1592 }],
1593 }
1594 }
1595 pub fn insert(&mut self, path: &[u32], id: u64) {
1597 let mut node_idx = 0;
1598 for &step in path {
1599 let child_idx = self.nodes[node_idx]
1600 .children
1601 .iter()
1602 .copied()
1603 .find(|&c| self.nodes[c].key == step);
1604 match child_idx {
1605 Some(ci) => node_idx = ci,
1606 None => {
1607 let new_idx = self.nodes.len();
1608 self.nodes.push(PathNode {
1609 key: step,
1610 value: None,
1611 children: Vec::new(),
1612 });
1613 self.nodes[node_idx].children.push(new_idx);
1614 node_idx = new_idx;
1615 }
1616 }
1617 }
1618 self.nodes[node_idx].value = Some(id);
1619 }
1620 pub fn get(&self, path: &[u32]) -> Option<u64> {
1622 let mut node_idx = 0;
1623 for &step in path {
1624 let child_idx = self.nodes[node_idx]
1625 .children
1626 .iter()
1627 .copied()
1628 .find(|&c| self.nodes[c].key == step)?;
1629 node_idx = child_idx;
1630 }
1631 self.nodes[node_idx].value
1632 }
1633 pub fn node_count(&self) -> usize {
1635 self.nodes.len()
1636 }
1637}
1638#[allow(dead_code)]
1640pub struct Stopwatch {
1641 start: std::time::Instant,
1642 splits: Vec<f64>,
1643}
1644#[allow(dead_code)]
1645impl Stopwatch {
1646 pub fn start() -> Self {
1648 Self {
1649 start: std::time::Instant::now(),
1650 splits: Vec::new(),
1651 }
1652 }
1653 pub fn split(&mut self) {
1655 self.splits.push(self.elapsed_ms());
1656 }
1657 pub fn elapsed_ms(&self) -> f64 {
1659 self.start.elapsed().as_secs_f64() * 1000.0
1660 }
1661 pub fn splits(&self) -> &[f64] {
1663 &self.splits
1664 }
1665 pub fn num_splits(&self) -> usize {
1667 self.splits.len()
1668 }
1669}
1670#[allow(dead_code)]
1672#[derive(Debug, Clone)]
1673pub struct SharedCacheEntry {
1674 pub id: u64,
1675 pub hash: u64,
1676 pub ref_count: u32,
1677}
1678#[allow(dead_code)]
1679impl SharedCacheEntry {
1680 pub fn new(id: u64, hash: u64) -> Self {
1682 SharedCacheEntry {
1683 id,
1684 hash,
1685 ref_count: 1,
1686 }
1687 }
1688 pub fn inc_ref(&mut self) {
1690 self.ref_count = self.ref_count.saturating_add(1);
1691 }
1692 pub fn dec_ref(&mut self) -> bool {
1694 if self.ref_count > 0 {
1695 self.ref_count -= 1;
1696 }
1697 self.ref_count > 0
1698 }
1699 pub fn is_dead(&self) -> bool {
1701 self.ref_count == 0
1702 }
1703}
1704#[allow(dead_code)]
1706pub struct PathBuf {
1707 components: Vec<String>,
1708}
1709#[allow(dead_code)]
1710impl PathBuf {
1711 pub fn new() -> Self {
1713 Self {
1714 components: Vec::new(),
1715 }
1716 }
1717 pub fn push(&mut self, comp: impl Into<String>) {
1719 self.components.push(comp.into());
1720 }
1721 pub fn pop(&mut self) {
1723 self.components.pop();
1724 }
1725 pub fn as_str(&self) -> String {
1727 self.components.join("/")
1728 }
1729 pub fn depth(&self) -> usize {
1731 self.components.len()
1732 }
1733 pub fn clear(&mut self) {
1735 self.components.clear();
1736 }
1737}
1738#[allow(dead_code)]
1740pub struct MemoTable {
1741 entries: Vec<(u64, u64)>,
1742}
1743#[allow(dead_code)]
1744impl MemoTable {
1745 pub fn new() -> Self {
1747 MemoTable {
1748 entries: Vec::new(),
1749 }
1750 }
1751 pub fn insert(&mut self, key: u64, val: u64) {
1753 if let Some(e) = self.entries.iter_mut().find(|(k, _)| *k == key) {
1754 e.1 = val;
1755 } else {
1756 self.entries.push((key, val));
1757 }
1758 }
1759 pub fn get(&self, key: u64) -> Option<u64> {
1761 self.entries
1762 .iter()
1763 .find(|(k, _)| *k == key)
1764 .map(|(_, v)| *v)
1765 }
1766 pub fn remove(&mut self, key: u64) -> Option<u64> {
1768 if let Some(pos) = self.entries.iter().position(|(k, _)| *k == key) {
1769 Some(self.entries.remove(pos).1)
1770 } else {
1771 None
1772 }
1773 }
1774 pub fn len(&self) -> usize {
1776 self.entries.len()
1777 }
1778 pub fn is_empty(&self) -> bool {
1780 self.entries.is_empty()
1781 }
1782 pub fn clear(&mut self) {
1784 self.entries.clear();
1785 }
1786 pub fn drain_all(&mut self) -> Vec<(u64, u64)> {
1788 let v = self.entries.clone();
1789 self.entries.clear();
1790 v
1791 }
1792}
1793#[derive(Clone, Debug)]
1798pub(crate) struct ExprKey(pub(crate) Expr);
1799pub struct ExprPool {
1805 hashcons: ExprHashcons,
1807 roots: Vec<ExprId>,
1809}
1810impl ExprPool {
1811 pub fn new() -> Self {
1813 ExprPool {
1814 hashcons: ExprHashcons::new(),
1815 roots: Vec::new(),
1816 }
1817 }
1818 pub fn add(&mut self, expr: Expr) -> ExprId {
1820 let (id, _) = self.hashcons.intern(expr);
1821 id
1822 }
1823 pub fn add_root(&mut self, expr: Expr) -> ExprId {
1825 let (id, _) = self.hashcons.intern(expr);
1826 self.roots.push(id);
1827 id
1828 }
1829 pub fn get(&self, id: ExprId) -> Option<&Expr> {
1831 self.hashcons.get(id)
1832 }
1833 pub fn mark_root(&mut self, id: ExprId) {
1838 self.roots.push(id);
1839 }
1840 pub fn live_count(&self) -> usize {
1844 let mut seen = std::collections::HashSet::new();
1845 for &id in &self.roots {
1846 seen.insert(id);
1847 }
1848 seen.len()
1849 }
1850 pub fn total_count(&self) -> usize {
1852 self.hashcons.size()
1853 }
1854 pub fn dedup_ratio(&self) -> f64 {
1859 self.hashcons.hit_rate()
1860 }
1861 pub fn get_id(&self, expr: &Expr) -> Option<ExprId> {
1863 self.hashcons.get_id(expr)
1864 }
1865}
1866#[allow(dead_code)]
1868pub struct WriteOnce<T> {
1869 value: std::cell::Cell<Option<T>>,
1870}
1871#[allow(dead_code)]
1872impl<T: Copy> WriteOnce<T> {
1873 pub fn new() -> Self {
1875 Self {
1876 value: std::cell::Cell::new(None),
1877 }
1878 }
1879 pub fn write(&self, val: T) -> bool {
1881 if self.value.get().is_some() {
1882 return false;
1883 }
1884 self.value.set(Some(val));
1885 true
1886 }
1887 pub fn read(&self) -> Option<T> {
1889 self.value.get()
1890 }
1891 pub fn is_written(&self) -> bool {
1893 self.value.get().is_some()
1894 }
1895}