use std::collections::HashMap;
use std::hash::{BuildHasherDefault, Hasher};
use crate::lang::Lang;
#[derive(Default)]
pub struct IdHasher(u64);
impl IdHasher {
#[inline]
fn mix(&mut self, v: u64) {
self.0 = (self.0.rotate_left(5) ^ v).wrapping_mul(0x517c_c1b7_2722_0a95);
}
}
impl Hasher for IdHasher {
#[inline]
fn finish(&self) -> u64 {
self.0
}
#[inline]
fn write(&mut self, bytes: &[u8]) {
for &b in bytes {
self.mix(b as u64);
}
}
#[inline]
fn write_u32(&mut self, i: u32) {
self.mix(i as u64);
}
#[inline]
fn write_u64(&mut self, i: u64) {
self.mix(i);
}
#[inline]
fn write_usize(&mut self, i: usize) {
self.mix(i as u64);
}
}
pub type IdBuild = BuildHasherDefault<IdHasher>;
pub(crate) type IdMap<K, V> = HashMap<K, V, IdBuild>;
pub type StrSet<'a> = std::collections::HashSet<&'a str, IdBuild>;
pub struct Walk<L: Lang> {
pub ids: Vec<L::Id>,
pub(crate) parents: IdMap<L::Id, (L::Id, usize)>,
pub root: L::Id,
}
impl<L: Lang> Walk<L> {
pub fn parent(&self, id: L::Id) -> Option<L::Id> {
self.parents.get(&id).map(|p| p.0)
}
pub fn index(&self, id: L::Id) -> Option<usize> {
self.parents.get(&id).map(|p| p.1)
}
}
pub fn walk<L: Lang>(lang: &L, root: L::Id) -> Walk<L> {
let mut ids = Vec::new();
let mut parents: IdMap<L::Id, (L::Id, usize)> = HashMap::default();
let mut stack: Vec<(L::Id, Option<(L::Id, usize)>)> = vec![(root, None)];
while let Some((id, par)) = stack.pop() {
if let Some((p, i)) = par {
parents.insert(id, (p, i));
}
ids.push(id);
let children = lang.children(id);
for (i, &c) in children.iter().enumerate().rev() {
stack.push((c, Some((id, i))));
}
}
Walk {
ids,
parents,
root,
}
}