use std::collections::HashMap;
use faststr::FastStr;
use crate::index::Index;
#[derive(Debug, Default)]
pub struct PointerTree {
size: usize,
pub(crate) root: PointerTreeNode,
}
impl PointerTree {
pub fn new() -> Self {
Self::default()
}
pub fn add_path<Path: IntoIterator>(&mut self, path: Path)
where
Path::Item: Index,
{
self.root.add_path(path, self.size);
self.size += 1;
}
pub fn size(&self) -> usize {
self.size
}
}
#[derive(Debug, Default)]
pub(crate) enum PointerTreeInner {
#[default]
Empty,
Key(MultiKey),
Index(MultiIndex),
}
#[derive(Debug, Default)]
pub(crate) struct PointerTreeNode {
pub(crate) order: Vec<usize>,
pub(crate) children: PointerTreeInner,
}
impl PointerTreeNode {
pub fn add_path<Path: IntoIterator>(&mut self, path: Path, order: usize)
where
Path::Item: Index,
{
let mut cur = self;
let iter = path.into_iter();
for p in iter {
if let Some(key) = p.as_key() {
if matches!(cur.children, PointerTreeInner::Empty) {
cur.children = PointerTreeInner::Key(HashMap::new());
}
cur = cur.insert_key(key)
} else if let Some(index) = p.as_index() {
if matches!(cur.children, PointerTreeInner::Empty) {
cur.children = PointerTreeInner::Index(HashMap::new());
}
cur = cur.insert_index(index)
}
}
cur.order.push(order);
}
fn insert_key(&mut self, key: &str) -> &mut Self {
if let PointerTreeInner::Key(mkey) = &mut self.children {
mkey.entry(FastStr::new(key)).or_insert(Self::default())
} else {
unreachable!()
}
}
fn insert_index(&mut self, idx: usize) -> &mut Self {
if let PointerTreeInner::Index(midx) = &mut self.children {
midx.entry(idx).or_insert(Self::default())
} else {
unreachable!()
}
}
}
#[allow(clippy::mutable_key_type)]
pub(crate) type MultiKey = HashMap<FastStr, PointerTreeNode>;
pub(crate) type MultiIndex = HashMap<usize, PointerTreeNode>;
#[cfg(test)]
mod test {
use super::*;
use crate::pointer;
#[test]
fn test_tree() {
let mut tree = PointerTree::default();
tree.add_path(["a", "a_b", "a_b_c"].iter());
tree.add_path(["a", "a_b"].iter());
tree.add_path(pointer!["a", "a_a", 1].iter());
tree.add_path(pointer!["a"].iter());
tree.add_path(pointer!["a"].iter());
tree.add_path(pointer!["b", 2].iter());
tree.add_path(pointer![].iter());
assert_eq!(tree.size(), 7);
println!("tree is {:#?}", tree);
}
}