use std::collections::{HashMap, HashSet, VecDeque};
#[allow(dead_code)]
pub struct LoopClock {
start: std::time::Instant,
iters: u64,
}
#[allow(dead_code)]
impl LoopClock {
pub fn start() -> Self {
Self {
start: std::time::Instant::now(),
iters: 0,
}
}
pub fn tick(&mut self) {
self.iters += 1;
}
pub fn elapsed_us(&self) -> f64 {
self.start.elapsed().as_secs_f64() * 1e6
}
pub fn avg_us_per_iter(&self) -> f64 {
if self.iters == 0 {
return 0.0;
}
self.elapsed_us() / self.iters as f64
}
pub fn iters(&self) -> u64 {
self.iters
}
}
#[allow(dead_code)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct Timestamp(u64);
#[allow(dead_code)]
impl Timestamp {
pub const fn from_us(us: u64) -> Self {
Self(us)
}
pub fn as_us(self) -> u64 {
self.0
}
pub fn elapsed_since(self, earlier: Timestamp) -> u64 {
self.0.saturating_sub(earlier.0)
}
}
#[derive(Debug, Clone)]
pub struct NameGenerator {
base: Name,
counter: u64,
}
impl NameGenerator {
pub fn new(base: Name) -> Self {
Self { base, counter: 0 }
}
pub fn with_base(s: impl Into<String>) -> Self {
Self::new(Name::str(s))
}
#[allow(clippy::should_implement_trait)]
pub fn next(&mut self) -> Name {
let n = self.base.clone().append_num(self.counter);
self.counter += 1;
n
}
pub fn peek(&self) -> Name {
self.base.clone().append_num(self.counter)
}
pub fn reset(&mut self) {
self.counter = 0;
}
pub fn count(&self) -> u64 {
self.counter
}
}
#[allow(dead_code)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TypedId<T> {
pub(super) id: u32,
_phantom: std::marker::PhantomData<T>,
}
#[allow(dead_code)]
impl<T> TypedId<T> {
pub const fn new(id: u32) -> Self {
Self {
id,
_phantom: std::marker::PhantomData,
}
}
pub fn raw(&self) -> u32 {
self.id
}
}
#[allow(dead_code)]
pub struct StringInterner {
strings: Vec<String>,
map: std::collections::HashMap<String, u32>,
}
#[allow(dead_code)]
impl StringInterner {
pub fn new() -> Self {
Self {
strings: Vec::new(),
map: std::collections::HashMap::new(),
}
}
pub fn intern(&mut self, s: &str) -> u32 {
if let Some(&id) = self.map.get(s) {
return id;
}
let id = self.strings.len() as u32;
self.strings.push(s.to_string());
self.map.insert(s.to_string(), id);
id
}
pub fn get(&self, id: u32) -> Option<&str> {
self.strings.get(id as usize).map(|s| s.as_str())
}
pub fn len(&self) -> usize {
self.strings.len()
}
pub fn is_empty(&self) -> bool {
self.strings.is_empty()
}
}
#[derive(Debug, Clone)]
pub struct NameTrie<V> {
pub(super) value: Option<V>,
pub(super) string_children: Vec<(String, NameTrie<V>)>,
pub(super) num_children: Vec<(u64, NameTrie<V>)>,
}
impl<V: Clone> NameTrie<V> {
pub fn new() -> Self {
Self::default()
}
pub fn insert(&mut self, name: &Name, value: V) {
match name {
Name::Anonymous => {
self.value = Some(value);
}
Name::Str(parent, s) => {
let child = if let Some(idx) = self.string_children.iter().position(|(k, _)| k == s)
{
&mut self.string_children[idx].1
} else {
self.string_children.push((s.clone(), NameTrie::new()));
let last = self.string_children.len() - 1;
&mut self.string_children[last].1
};
child.insert(parent, value);
}
Name::Num(parent, n) => {
let child = if let Some(idx) = self.num_children.iter().position(|(k, _)| k == n) {
&mut self.num_children[idx].1
} else {
self.num_children.push((*n, NameTrie::new()));
let last = self.num_children.len() - 1;
&mut self.num_children[last].1
};
child.insert(parent, value);
}
}
}
pub fn lookup(&self, name: &Name) -> Option<&V> {
match name {
Name::Anonymous => self.value.as_ref(),
Name::Str(parent, s) => {
let child = self
.string_children
.iter()
.find(|(k, _)| k == s)
.map(|(_, v)| v)?;
child.lookup(parent)
}
Name::Num(parent, n) => {
let child = self
.num_children
.iter()
.find(|(k, _)| k == n)
.map(|(_, v)| v)?;
child.lookup(parent)
}
}
}
pub fn contains(&self, name: &Name) -> bool {
self.lookup(name).is_some()
}
pub fn count(&self) -> usize {
let self_count = if self.value.is_some() { 1 } else { 0 };
let str_count: usize = self.string_children.iter().map(|(_, c)| c.count()).sum();
let num_count: usize = self.num_children.iter().map(|(_, c)| c.count()).sum();
self_count + str_count + num_count
}
pub fn to_vec(&self) -> Vec<(Name, V)> {
let mut result = Vec::new();
self.collect_all(Name::Anonymous, &mut result);
result
}
fn collect_all(&self, prefix: Name, result: &mut Vec<(Name, V)>) {
if let Some(v) = &self.value {
result.push((prefix.clone(), v.clone()));
}
for (s, child) in &self.string_children {
let name = prefix.clone().append_str(s.as_str());
child.collect_all(name, result);
}
for (n, child) in &self.num_children {
let name = prefix.clone().append_num(*n);
child.collect_all(name, result);
}
}
}
#[allow(dead_code)]
pub struct WorkQueue<T> {
items: std::collections::VecDeque<T>,
}
#[allow(dead_code)]
impl<T> WorkQueue<T> {
pub fn new() -> Self {
Self {
items: std::collections::VecDeque::new(),
}
}
pub fn enqueue(&mut self, item: T) {
self.items.push_back(item);
}
pub fn dequeue(&mut self) -> Option<T> {
self.items.pop_front()
}
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
pub fn len(&self) -> usize {
self.items.len()
}
}
#[allow(dead_code)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SeqNum(u64);
#[allow(dead_code)]
impl SeqNum {
pub const ZERO: SeqNum = SeqNum(0);
pub fn next(self) -> SeqNum {
SeqNum(self.0 + 1)
}
pub fn value(self) -> u64 {
self.0
}
}
#[allow(dead_code)]
pub struct IntervalSet {
intervals: Vec<(i64, i64)>,
}
#[allow(dead_code)]
impl IntervalSet {
pub fn new() -> Self {
Self {
intervals: Vec::new(),
}
}
pub fn add(&mut self, lo: i64, hi: i64) {
if lo > hi {
return;
}
let mut new_lo = lo;
let mut new_hi = hi;
let mut i = 0;
while i < self.intervals.len() {
let (il, ih) = self.intervals[i];
if ih < new_lo - 1 {
i += 1;
continue;
}
if il > new_hi + 1 {
break;
}
new_lo = new_lo.min(il);
new_hi = new_hi.max(ih);
self.intervals.remove(i);
}
self.intervals.insert(i, (new_lo, new_hi));
}
pub fn contains(&self, x: i64) -> bool {
self.intervals.iter().any(|&(lo, hi)| x >= lo && x <= hi)
}
pub fn num_intervals(&self) -> usize {
self.intervals.len()
}
pub fn cardinality(&self) -> i64 {
self.intervals.iter().map(|&(lo, hi)| hi - lo + 1).sum()
}
}
#[derive(Debug, Clone, Default)]
pub struct NameMap<V> {
pub(super) inner: HashMap<Name, V>,
}
impl<V> NameMap<V> {
pub fn new() -> Self {
Self {
inner: HashMap::new(),
}
}
pub fn with_capacity(cap: usize) -> Self {
Self {
inner: HashMap::with_capacity(cap),
}
}
pub fn insert(&mut self, name: Name, value: V) -> Option<V> {
self.inner.insert(name, value)
}
pub fn get(&self, name: &Name) -> Option<&V> {
self.inner.get(name)
}
pub fn get_mut(&mut self, name: &Name) -> Option<&mut V> {
self.inner.get_mut(name)
}
pub fn remove(&mut self, name: &Name) -> Option<V> {
self.inner.remove(name)
}
pub fn contains_key(&self, name: &Name) -> bool {
self.inner.contains_key(name)
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = (&Name, &V)> {
self.inner.iter()
}
pub fn keys(&self) -> impl Iterator<Item = &Name> {
self.inner.keys()
}
pub fn values(&self) -> impl Iterator<Item = &V> {
self.inner.values()
}
pub fn filter_by_namespace(&self, ns: &Name) -> Vec<(&Name, &V)> {
self.inner
.iter()
.filter(|(n, _)| n.has_prefix(ns))
.collect()
}
pub fn sorted_names(&self) -> Vec<Name> {
let mut names: Vec<Name> = self.inner.keys().cloned().collect();
names.sort();
names
}
pub fn entry_or_insert(&mut self, name: Name, value: V) -> &mut V {
self.inner.entry(name).or_insert(value)
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub struct BeforeAfter<T> {
pub before: T,
pub after: T,
}
#[allow(dead_code)]
impl<T: PartialEq> BeforeAfter<T> {
pub fn new(before: T, after: T) -> Self {
Self { before, after }
}
pub fn unchanged(&self) -> bool {
self.before == self.after
}
}
#[allow(dead_code)]
pub struct WorkStack<T> {
items: Vec<T>,
}
#[allow(dead_code)]
impl<T> WorkStack<T> {
pub fn new() -> Self {
Self { items: Vec::new() }
}
pub fn push(&mut self, item: T) {
self.items.push(item);
}
pub fn pop(&mut self) -> Option<T> {
self.items.pop()
}
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
pub fn len(&self) -> usize {
self.items.len()
}
}
#[allow(dead_code)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Generation(u32);
#[allow(dead_code)]
impl Generation {
pub const INITIAL: Generation = Generation(0);
pub fn advance(self) -> Generation {
Generation(self.0 + 1)
}
pub fn number(self) -> u32 {
self.0
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct QualifiedName {
pub canonical: Name,
pub alias: Option<Name>,
}
impl QualifiedName {
pub fn new(canonical: Name) -> Self {
Self {
canonical,
alias: None,
}
}
pub fn with_alias(canonical: Name, alias: Name) -> Self {
Self {
canonical,
alias: Some(alias),
}
}
pub fn preferred(&self) -> &Name {
self.alias.as_ref().unwrap_or(&self.canonical)
}
}
#[allow(dead_code)]
pub struct NamePool {
names: Vec<String>,
index: std::collections::HashMap<String, usize>,
}
#[allow(dead_code)]
impl NamePool {
pub fn new() -> Self {
Self {
names: Vec::new(),
index: std::collections::HashMap::new(),
}
}
pub fn intern(&mut self, name: &str) -> usize {
if let Some(&id) = self.index.get(name) {
return id;
}
let id = self.names.len();
self.names.push(name.to_string());
self.index.insert(name.to_string(), id);
id
}
pub fn get(&self, id: usize) -> Option<&str> {
self.names.get(id).map(|s| s.as_str())
}
pub fn len(&self) -> usize {
self.names.len()
}
pub fn is_empty(&self) -> bool {
self.names.is_empty()
}
}
#[allow(dead_code)]
pub struct NameResolver {
namespace: Vec<String>,
registered: std::collections::HashSet<String>,
}
#[allow(dead_code)]
impl NameResolver {
pub fn new() -> Self {
Self {
namespace: Vec::new(),
registered: std::collections::HashSet::new(),
}
}
pub fn register(&mut self, fqn: impl Into<String>) {
self.registered.insert(fqn.into());
}
pub fn enter(&mut self, ns: impl Into<String>) {
self.namespace.push(ns.into());
}
pub fn exit(&mut self) {
self.namespace.pop();
}
pub fn current_ns(&self) -> String {
self.namespace.join(".")
}
pub fn resolve(&self, name: &str) -> String {
if self.namespace.is_empty() {
return name.to_string();
}
let fqn = format!("{}.{}", self.namespace.join("."), name);
if self.registered.contains(&fqn) {
fqn
} else {
name.to_string()
}
}
}
#[allow(dead_code)]
pub struct RingBuffer<T> {
data: Vec<Option<T>>,
head: usize,
tail: usize,
count: usize,
capacity: usize,
}
#[allow(dead_code)]
impl<T> RingBuffer<T> {
pub fn new(capacity: usize) -> Self {
let mut data = Vec::with_capacity(capacity);
for _ in 0..capacity {
data.push(None);
}
Self {
data,
head: 0,
tail: 0,
count: 0,
capacity,
}
}
pub fn push(&mut self, val: T) {
if self.count == self.capacity {
self.data[self.head] = Some(val);
self.head = (self.head + 1) % self.capacity;
self.tail = (self.tail + 1) % self.capacity;
} else {
self.data[self.tail] = Some(val);
self.tail = (self.tail + 1) % self.capacity;
self.count += 1;
}
}
pub fn pop(&mut self) -> Option<T> {
if self.count == 0 {
return None;
}
let val = self.data[self.head].take();
self.head = (self.head + 1) % self.capacity;
self.count -= 1;
val
}
pub fn len(&self) -> usize {
self.count
}
pub fn is_empty(&self) -> bool {
self.count == 0
}
pub fn is_full(&self) -> bool {
self.count == self.capacity
}
}
#[allow(dead_code)]
pub struct BiMap<A: std::hash::Hash + Eq + Clone, B: std::hash::Hash + Eq + Clone> {
forward: std::collections::HashMap<A, B>,
backward: std::collections::HashMap<B, A>,
}
#[allow(dead_code)]
impl<A: std::hash::Hash + Eq + Clone, B: std::hash::Hash + Eq + Clone> BiMap<A, B> {
pub fn new() -> Self {
Self {
forward: std::collections::HashMap::new(),
backward: std::collections::HashMap::new(),
}
}
pub fn insert(&mut self, a: A, b: B) {
self.forward.insert(a.clone(), b.clone());
self.backward.insert(b, a);
}
pub fn get_b(&self, a: &A) -> Option<&B> {
self.forward.get(a)
}
pub fn get_a(&self, b: &B) -> Option<&A> {
self.backward.get(b)
}
pub fn len(&self) -> usize {
self.forward.len()
}
pub fn is_empty(&self) -> bool {
self.forward.is_empty()
}
}
#[derive(Clone, PartialEq, Eq, Hash, Debug, Default)]
pub enum Name {
#[default]
Anonymous,
Str(Box<Name>, String),
Num(Box<Name>, u64),
}
impl Name {
pub fn str(s: impl Into<String>) -> Self {
Name::Str(Box::new(Name::Anonymous), s.into())
}
pub fn append_str(self, s: impl Into<String>) -> Self {
Name::Str(Box::new(self), s.into())
}
pub fn append_num(self, n: u64) -> Self {
Name::Num(Box::new(self), n)
}
pub fn is_anonymous(&self) -> bool {
matches!(self, Name::Anonymous)
}
#[allow(clippy::should_implement_trait)]
pub fn from_str(s: &str) -> Self {
let mut parts = s.split('.');
let first = match parts.next() {
None | Some("") => return Name::Anonymous,
Some(f) => f,
};
let mut name = Name::str(first);
for part in parts {
if part.is_empty() {
continue;
}
if let Ok(n) = part.parse::<u64>() {
name = name.append_num(n);
} else {
name = name.append_str(part);
}
}
name
}
pub fn depth(&self) -> usize {
match self {
Name::Anonymous => 0,
Name::Str(parent, _) | Name::Num(parent, _) => 1 + parent.depth(),
}
}
pub fn last_str(&self) -> Option<&str> {
match self {
Name::Anonymous => None,
Name::Str(_, s) => Some(s.as_str()),
Name::Num(parent, _) => parent.last_str(),
}
}
pub fn last_num(&self) -> Option<u64> {
match self {
Name::Num(_, n) => Some(*n),
Name::Str(parent, _) => parent.last_num(),
Name::Anonymous => None,
}
}
pub fn root(&self) -> Option<&str> {
match self {
Name::Anonymous => None,
Name::Str(parent, s) => {
if parent.is_anonymous() {
Some(s.as_str())
} else {
parent.root()
}
}
Name::Num(parent, _) => parent.root(),
}
}
pub fn prefix(&self) -> Name {
match self {
Name::Anonymous => Name::Anonymous,
Name::Str(parent, _) | Name::Num(parent, _) => *parent.clone(),
}
}
pub fn has_prefix(&self, prefix: &Name) -> bool {
if self == prefix {
return false;
}
let mut current = self;
loop {
match current {
Name::Anonymous => return false,
Name::Str(parent, _) | Name::Num(parent, _) => {
if parent.as_ref() == prefix {
return true;
}
current = parent;
}
}
}
}
pub fn components(&self) -> Vec<String> {
let mut comps = Vec::new();
let mut current = self;
loop {
match current {
Name::Anonymous => break,
Name::Str(parent, s) => {
comps.push(s.clone());
current = parent;
}
Name::Num(parent, n) => {
comps.push(n.to_string());
current = parent;
}
}
}
comps.reverse();
comps
}
pub fn from_components(comps: &[String]) -> Self {
let mut name = Name::Anonymous;
for comp in comps {
if let Ok(n) = comp.parse::<u64>() {
name = name.append_num(n);
} else {
name = name.append_str(comp.as_str());
}
}
name
}
pub fn replace_last(self, new_last: impl Into<String>) -> Self {
match self {
Name::Anonymous => Name::str(new_last),
Name::Str(parent, _) => Name::Str(parent, new_last.into()),
Name::Num(parent, _) => Name::Str(parent, new_last.into()),
}
}
pub fn freshen(self, suffix: u64) -> Self {
self.append_num(suffix)
}
pub fn in_namespace(&self, ns: &Name) -> bool {
self.has_prefix(ns)
}
pub fn with_suffix(self, suffix: impl Into<String>) -> Self {
self.append_str(suffix)
}
pub fn to_ident_string(&self) -> String {
self.to_string()
.chars()
.map(|c| {
if c.is_alphanumeric() || c == '_' {
c
} else {
'_'
}
})
.collect()
}
pub fn prepend(self, prefix: Name) -> Self {
let comps = self.components();
let mut name = prefix;
for comp in comps {
if let Ok(n) = comp.parse::<u64>() {
name = name.append_num(n);
} else {
name = name.append_str(comp);
}
}
name
}
pub fn is_str_name(&self) -> bool {
matches!(self, Name::Str(_, _))
}
pub fn is_num_name(&self) -> bool {
matches!(self, Name::Num(_, _))
}
}
#[allow(dead_code)]
pub struct NameMapping {
name_to_id: std::collections::HashMap<String, u32>,
id_to_name: std::collections::HashMap<u32, String>,
next_id: u32,
}
#[allow(dead_code)]
impl NameMapping {
pub fn new() -> Self {
Self {
name_to_id: std::collections::HashMap::new(),
id_to_name: std::collections::HashMap::new(),
next_id: 0,
}
}
pub fn register(&mut self, name: impl Into<String>) -> u32 {
let name = name.into();
if let Some(&id) = self.name_to_id.get(&name) {
return id;
}
let id = self.next_id;
self.next_id += 1;
self.name_to_id.insert(name.clone(), id);
self.id_to_name.insert(id, name);
id
}
pub fn id_of(&self, name: &str) -> Option<u32> {
self.name_to_id.get(name).copied()
}
pub fn name_of(&self, id: u32) -> Option<&str> {
self.id_to_name.get(&id).map(|s| s.as_str())
}
pub fn len(&self) -> usize {
self.name_to_id.len()
}
pub fn is_empty(&self) -> bool {
self.name_to_id.is_empty()
}
}
#[allow(dead_code)]
pub struct DiagMeta {
pub(super) entries: Vec<(String, String)>,
}
#[allow(dead_code)]
impl DiagMeta {
pub fn new() -> Self {
Self {
entries: Vec::new(),
}
}
pub fn add(&mut self, key: impl Into<String>, val: impl Into<String>) {
self.entries.push((key.into(), val.into()));
}
pub fn get(&self, key: &str) -> Option<&str> {
self.entries
.iter()
.find(|(k, _)| k == key)
.map(|(_, v)| v.as_str())
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
}
#[allow(dead_code)]
pub struct SparseBitSet {
words: Vec<u64>,
}
#[allow(dead_code)]
impl SparseBitSet {
pub fn new(capacity: usize) -> Self {
let words = (capacity + 63) / 64;
Self {
words: vec![0u64; words],
}
}
pub fn set(&mut self, i: usize) {
let word = i / 64;
let bit = i % 64;
if word < self.words.len() {
self.words[word] |= 1u64 << bit;
}
}
pub fn clear(&mut self, i: usize) {
let word = i / 64;
let bit = i % 64;
if word < self.words.len() {
self.words[word] &= !(1u64 << bit);
}
}
pub fn get(&self, i: usize) -> bool {
let word = i / 64;
let bit = i % 64;
self.words.get(word).is_some_and(|w| w & (1u64 << bit) != 0)
}
pub fn count_ones(&self) -> u32 {
self.words.iter().map(|w| w.count_ones()).sum()
}
pub fn union(&self, other: &SparseBitSet) -> SparseBitSet {
let len = self.words.len().max(other.words.len());
let mut result = SparseBitSet {
words: vec![0u64; len],
};
for i in 0..self.words.len() {
result.words[i] |= self.words[i];
}
for i in 0..other.words.len() {
result.words[i] |= other.words[i];
}
result
}
}
#[allow(dead_code)]
pub struct NameSetExt {
inner: std::collections::HashSet<String>,
}
#[allow(dead_code)]
impl NameSetExt {
pub fn new() -> Self {
Self {
inner: std::collections::HashSet::new(),
}
}
pub fn insert(&mut self, name: impl Into<String>) {
self.inner.insert(name.into());
}
pub fn contains(&self, name: &str) -> bool {
self.inner.contains(name)
}
pub fn remove(&mut self, name: &str) {
self.inner.remove(name);
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn union(&self, other: &NameSetExt) -> NameSetExt {
let mut result = NameSetExt::new();
for n in &self.inner {
result.insert(n.as_str());
}
for n in &other.inner {
result.insert(n.as_str());
}
result
}
pub fn intersect(&self, other: &NameSetExt) -> NameSetExt {
let mut result = NameSetExt::new();
for n in &self.inner {
if other.contains(n) {
result.insert(n.as_str());
}
}
result
}
}
#[allow(dead_code)]
pub struct ScopeStack {
names: Vec<String>,
}
#[allow(dead_code)]
impl ScopeStack {
pub fn new() -> Self {
Self { names: Vec::new() }
}
pub fn push(&mut self, name: impl Into<String>) {
self.names.push(name.into());
}
pub fn pop(&mut self) -> Option<String> {
self.names.pop()
}
pub fn current(&self) -> Option<&str> {
self.names.last().map(|s| s.as_str())
}
pub fn depth(&self) -> usize {
self.names.len()
}
pub fn is_empty(&self) -> bool {
self.names.is_empty()
}
pub fn path(&self) -> String {
self.names.join(".")
}
}
#[allow(dead_code)]
pub struct NameTrieExt {
children: std::collections::HashMap<char, NameTrieExt>,
terminal: bool,
name: Option<String>,
}
#[allow(dead_code)]
impl NameTrieExt {
pub fn new() -> Self {
Self {
children: std::collections::HashMap::new(),
terminal: false,
name: None,
}
}
pub fn insert(&mut self, name: &str) {
let mut node = self;
for c in name.chars() {
node = node.children.entry(c).or_default();
}
node.terminal = true;
node.name = Some(name.to_string());
}
pub fn contains(&self, name: &str) -> bool {
let mut node = self;
for c in name.chars() {
match node.children.get(&c) {
Some(n) => node = n,
None => return false,
}
}
node.terminal
}
pub fn with_prefix(&self, prefix: &str) -> Vec<String> {
let mut node = self;
for c in prefix.chars() {
match node.children.get(&c) {
Some(n) => node = n,
None => return Vec::new(),
}
}
let mut results = Vec::new();
node.collect_all(&mut results);
results
}
fn collect_all(&self, out: &mut Vec<String>) {
if let Some(ref n) = self.name {
out.push(n.clone());
}
for child in self.children.values() {
let c: &NameTrieExt = child;
c.collect_all(out);
}
}
}
#[allow(dead_code)]
pub struct EventCounter {
counts: std::collections::HashMap<String, u64>,
}
#[allow(dead_code)]
impl EventCounter {
pub fn new() -> Self {
Self {
counts: std::collections::HashMap::new(),
}
}
pub fn inc(&mut self, event: &str) {
*self.counts.entry(event.to_string()).or_insert(0) += 1;
}
pub fn add(&mut self, event: &str, n: u64) {
*self.counts.entry(event.to_string()).or_insert(0) += n;
}
pub fn get(&self, event: &str) -> u64 {
self.counts.get(event).copied().unwrap_or(0)
}
pub fn total(&self) -> u64 {
self.counts.values().sum()
}
pub fn reset(&mut self) {
self.counts.clear();
}
pub fn event_names(&self) -> Vec<&str> {
self.counts.keys().map(|s| s.as_str()).collect()
}
}
#[derive(Debug, Clone, Default)]
pub struct NameSet {
pub(super) inner: HashSet<Name>,
}
impl NameSet {
pub fn new() -> Self {
Self {
inner: HashSet::new(),
}
}
pub fn insert(&mut self, name: Name) -> bool {
self.inner.insert(name)
}
pub fn remove(&mut self, name: &Name) -> bool {
self.inner.remove(name)
}
pub fn contains(&self, name: &Name) -> bool {
self.inner.contains(name)
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = &Name> {
self.inner.iter()
}
pub fn union(&self, other: &NameSet) -> NameSet {
NameSet {
inner: self.inner.union(&other.inner).cloned().collect(),
}
}
pub fn intersection(&self, other: &NameSet) -> NameSet {
NameSet {
inner: self.inner.intersection(&other.inner).cloned().collect(),
}
}
pub fn difference(&self, other: &NameSet) -> NameSet {
NameSet {
inner: self.inner.difference(&other.inner).cloned().collect(),
}
}
pub fn in_namespace(&self, ns: &Name) -> NameSet {
NameSet {
inner: self
.inner
.iter()
.filter(|n| n.has_prefix(ns))
.cloned()
.collect(),
}
}
pub fn to_sorted_vec(&self) -> Vec<Name> {
let mut v: Vec<Name> = self.inner.iter().cloned().collect();
v.sort();
v
}
}
#[allow(dead_code)]
pub struct AnnotationTable {
map: std::collections::HashMap<String, Vec<String>>,
}
#[allow(dead_code)]
impl AnnotationTable {
pub fn new() -> Self {
Self {
map: std::collections::HashMap::new(),
}
}
pub fn annotate(&mut self, key: impl Into<String>, val: impl Into<String>) {
self.map.entry(key.into()).or_default().push(val.into());
}
pub fn get_all(&self, key: &str) -> &[String] {
self.map.get(key).map(|v| v.as_slice()).unwrap_or(&[])
}
pub fn num_keys(&self) -> usize {
self.map.len()
}
pub fn has(&self, key: &str) -> bool {
self.map.contains_key(key)
}
}
#[allow(dead_code)]
pub struct SimpleLruCache<K: std::hash::Hash + Eq + Clone, V: Clone> {
capacity: usize,
map: std::collections::HashMap<K, usize>,
keys: Vec<K>,
vals: Vec<V>,
order: Vec<usize>,
}
#[allow(dead_code)]
impl<K: std::hash::Hash + Eq + Clone, V: Clone> SimpleLruCache<K, V> {
pub fn new(capacity: usize) -> Self {
assert!(capacity > 0);
Self {
capacity,
map: std::collections::HashMap::new(),
keys: Vec::new(),
vals: Vec::new(),
order: Vec::new(),
}
}
pub fn put(&mut self, key: K, val: V) {
if let Some(&idx) = self.map.get(&key) {
self.vals[idx] = val;
self.order.retain(|&x| x != idx);
self.order.insert(0, idx);
return;
}
if self.keys.len() >= self.capacity {
let evict_idx = *self
.order
.last()
.expect("order list must be non-empty before eviction");
self.map.remove(&self.keys[evict_idx]);
self.order.pop();
self.keys[evict_idx] = key.clone();
self.vals[evict_idx] = val;
self.map.insert(key, evict_idx);
self.order.insert(0, evict_idx);
} else {
let idx = self.keys.len();
self.keys.push(key.clone());
self.vals.push(val);
self.map.insert(key, idx);
self.order.insert(0, idx);
}
}
pub fn get(&mut self, key: &K) -> Option<&V> {
let idx = *self.map.get(key)?;
self.order.retain(|&x| x != idx);
self.order.insert(0, idx);
Some(&self.vals[idx])
}
pub fn len(&self) -> usize {
self.keys.len()
}
pub fn is_empty(&self) -> bool {
self.keys.is_empty()
}
}
#[allow(dead_code)]
pub struct Slot<T> {
inner: Option<T>,
}
#[allow(dead_code)]
impl<T> Slot<T> {
pub fn empty() -> Self {
Self { inner: None }
}
pub fn fill(&mut self, val: T) {
assert!(self.inner.is_none(), "Slot: already filled");
self.inner = Some(val);
}
pub fn get(&self) -> Option<&T> {
self.inner.as_ref()
}
pub fn is_filled(&self) -> bool {
self.inner.is_some()
}
pub fn take(&mut self) -> Option<T> {
self.inner.take()
}
pub fn get_or_fill_with(&mut self, f: impl FnOnce() -> T) -> &T {
if self.inner.is_none() {
self.inner = Some(f());
}
self.inner
.as_ref()
.expect("inner value must be initialized before access")
}
}
#[allow(dead_code)]
pub struct NameGeneratorExt {
prefix: String,
counter: u64,
}
#[allow(dead_code)]
impl NameGeneratorExt {
pub fn new(prefix: impl Into<String>) -> Self {
Self {
prefix: prefix.into(),
counter: 0,
}
}
#[allow(clippy::should_implement_trait)]
pub fn next(&mut self) -> String {
let n = self.counter;
self.counter += 1;
format!("{}{}", self.prefix, n)
}
pub fn count(&self) -> u64 {
self.counter
}
pub fn reset(&mut self) {
self.counter = 0;
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub struct StatCache<K: std::hash::Hash + Eq + Clone, V: Clone> {
pub inner: SimpleLruCache<K, V>,
pub hits: u64,
pub misses: u64,
}
#[allow(dead_code)]
impl<K: std::hash::Hash + Eq + Clone, V: Clone> StatCache<K, V> {
pub fn new(capacity: usize) -> Self {
Self {
inner: SimpleLruCache::new(capacity),
hits: 0,
misses: 0,
}
}
pub fn get(&mut self, key: &K) -> Option<&V> {
let result = self.inner.get(key);
if result.is_some() {
self.hits += 1;
} else {
self.misses += 1;
}
None
}
pub fn put(&mut self, key: K, val: V) {
self.inner.put(key, val);
}
pub fn hit_rate(&self) -> f64 {
let total = self.hits + self.misses;
if total == 0 {
return 0.0;
}
self.hits as f64 / total as f64
}
}
#[allow(dead_code)]
pub struct FrequencyTable<T: std::hash::Hash + Eq + Clone> {
counts: std::collections::HashMap<T, u64>,
}
#[allow(dead_code)]
impl<T: std::hash::Hash + Eq + Clone> FrequencyTable<T> {
pub fn new() -> Self {
Self {
counts: std::collections::HashMap::new(),
}
}
pub fn record(&mut self, item: T) {
*self.counts.entry(item).or_insert(0) += 1;
}
pub fn freq(&self, item: &T) -> u64 {
self.counts.get(item).copied().unwrap_or(0)
}
pub fn most_frequent(&self) -> Option<(&T, u64)> {
self.counts
.iter()
.max_by_key(|(_, &v)| v)
.map(|(k, &v)| (k, v))
}
pub fn total(&self) -> u64 {
self.counts.values().sum()
}
pub fn distinct(&self) -> usize {
self.counts.len()
}
}
#[allow(dead_code)]
pub struct IdDispenser<T> {
next: u32,
_phantom: std::marker::PhantomData<T>,
}
#[allow(dead_code)]
impl<T> IdDispenser<T> {
pub fn new() -> Self {
Self {
next: 0,
_phantom: std::marker::PhantomData,
}
}
#[allow(clippy::should_implement_trait)]
pub fn next(&mut self) -> TypedId<T> {
let id = TypedId::new(self.next);
self.next += 1;
id
}
pub fn count(&self) -> u32 {
self.next
}
}
#[allow(dead_code)]
#[allow(missing_docs)]
pub struct QualifiedNameExt {
pub parts: Vec<String>,
}
#[allow(dead_code)]
impl QualifiedNameExt {
pub fn from_dot_str(s: &str) -> Self {
s.parse().unwrap_or_else(|_| unreachable!())
}
pub fn simple(name: impl Into<String>) -> Self {
Self {
parts: vec![name.into()],
}
}
pub fn unqualified(&self) -> &str {
self.parts.last().map(|s| s.as_str()).unwrap_or("")
}
pub fn namespace(&self) -> Option<QualifiedNameExt> {
if self.parts.len() <= 1 {
return None;
}
let parts = self.parts[..self.parts.len() - 1].to_vec();
Some(QualifiedNameExt { parts })
}
pub fn is_sub_of(&self, other: &QualifiedNameExt) -> bool {
self.parts.starts_with(&other.parts)
}
pub fn depth(&self) -> usize {
self.parts.len()
}
}
#[allow(dead_code)]
pub struct MemoSlot<T: Clone> {
cached: Option<T>,
}
#[allow(dead_code)]
impl<T: Clone> MemoSlot<T> {
pub fn new() -> Self {
Self { cached: None }
}
pub fn get_or_compute(&mut self, f: impl FnOnce() -> T) -> &T {
if self.cached.is_none() {
self.cached = Some(f());
}
self.cached
.as_ref()
.expect("cached value must be initialized before access")
}
pub fn invalidate(&mut self) {
self.cached = None;
}
pub fn is_cached(&self) -> bool {
self.cached.is_some()
}
}