use smallvec::SmallVec;
use std::{collections::HashSet, slice::Iter};
#[derive(Debug, Default)]
pub(crate) struct Dag<T> {
arena: Vec<Node<T>>,
}
impl<T> Dag<T> {
pub(crate) fn new() -> Self {
Dag { arena: Vec::new() }
}
pub(crate) fn add(&mut self, data: T) -> usize {
let idx = self.arena.len();
self.arena.push(Node::new(data));
idx
}
pub(crate) fn get(&self, idx: usize) -> Option<&Node<T>> {
self.arena.get(idx)
}
fn get_mut(&mut self, idx: usize) -> Option<&mut Node<T>> {
self.arena.get_mut(idx)
}
pub(crate) fn iter(&self) -> Iter<'_, Node<T>> {
self.arena.iter()
}
pub(crate) fn entry(&mut self, idx: usize) -> Entry<'_, T> {
Entry { idx, dag: self }
}
pub(crate) fn depth(&self, idx: usize) -> Option<usize> {
if idx >= self.arena.len() {
return None;
}
let mut to_visit = HashSet::new();
to_visit.insert(0);
let mut buf = HashSet::new();
let mut depth = 0;
while !to_visit.contains(&idx) {
for id in to_visit.drain() {
buf.extend(self.get(id).expect("Should be valid").children.iter());
}
std::mem::swap(&mut to_visit, &mut buf);
depth += 1;
}
Some(depth)
}
}
#[derive(Debug, Default)]
pub(crate) struct Node<T> {
pub(crate) data: T,
pub(crate) children: SmallVec<[usize; 2]>,
}
impl<T> Node<T> {
fn new(data: T) -> Self {
Node {
data,
children: SmallVec::new(),
}
}
}
pub(crate) struct Entry<'a, T> {
idx: usize,
dag: &'a mut Dag<T>,
}
impl<T> Entry<'_, T> {
pub(crate) fn append_new(&mut self, data: T) -> Option<usize> {
let dag = &mut self.dag;
let new_idx = dag.add(data);
self.append(new_idx)
}
pub(crate) fn append(&mut self, idx: usize) -> Option<usize> {
if self.dag.get(idx).is_some() {
self.dag.arena[self.idx].children.push(idx);
Some(idx)
} else {
None
}
}
pub(crate) fn and_modify<F>(self, f: F) -> Self
where
F: FnOnce(&mut T),
{
if let Some(node) = self.dag.get_mut(self.idx) {
f(&mut node.data);
}
self
}
}
#[cfg(test)]
mod tests {
use super::*;
impl<T> Dag<T> {
pub fn count(&self) -> usize {
self.arena.len()
}
}
#[test]
fn create_empty_dag() {
let dag = Dag::<usize>::new();
assert_eq!(dag.count(), 0);
}
#[test]
fn create_node() {
let node = Node::new(0);
assert_eq!(node.children.len(), 0);
}
#[test]
fn add_node_to_dag() {
let mut dag = Dag::new();
let idx_42 = dag.add(42);
assert_eq!(idx_42, 0);
assert_eq!(dag.count(), 1);
assert_eq!(dag.depth(idx_42), Some(0));
let idx_314 = dag.entry(idx_42).append_new(314).unwrap();
assert_eq!(idx_314, 1);
assert_eq!(dag.count(), 2);
assert_eq!(dag.depth(idx_314), Some(1));
assert_eq!(dag.depth(2), None);
}
#[test]
fn dag_iter() {
let mut dag = Dag::new();
dag.add(42);
dag.add(314);
let values: Vec<usize> = dag.iter().map(|node| node.data).collect();
assert_eq!(&values, &[42, 314]);
}
}