use alloc::collections::VecDeque;
use crate::dynamic::hierarchy::Hierarchy;
use crate::dynamic::InternalNodeId;
use crate::nonmax::NonMaxUsize;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum DftEvent<Id> {
Open(Id),
Close(Id),
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct DepthFirstTraverser<Id> {
next: Option<(DftEvent<Id>, DftEvent<Id>)>,
}
impl<Id: InternalNodeId> DepthFirstTraverser<Id> {
#[must_use]
pub(crate) fn with_toplevel(id: Id, hier: &Hierarchy<Id>) -> Self {
if !hier.is_alive(id) {
panic!("[precondition] the node to be traversed must be alive");
}
Self {
next: Some((DftEvent::Open(id), DftEvent::Close(id))),
}
}
pub(crate) fn next(&mut self, hier: &Hierarchy<Id>) -> Option<DftEvent<Id>> {
let (next, next_back) = self.next?;
match self.next_of_next_forward(hier) {
Some(next_of_next) => {
self.next = Some((next_of_next, next_back));
}
None => {
self.next = None;
}
}
Some(next)
}
pub(crate) fn next_back(&mut self, hier: &Hierarchy<Id>) -> Option<DftEvent<Id>> {
let (next, next_back) = self.next?;
match self.next_of_next_backward(hier) {
Some(next_of_next_back) => {
self.next = Some((next, next_of_next_back));
}
None => {
self.next = None;
}
}
Some(next_back)
}
fn next_of_next_forward(&mut self, hier: &Hierarchy<Id>) -> Option<DftEvent<Id>> {
let (next, next_back) = self.next?;
if next == next_back {
return None;
}
match next {
DftEvent::Open(id) => {
let neighbors = hier
.neighbors(id)
.expect("[consistency] the node being traversed must be alive");
Some(match neighbors.first_child() {
Some(first_child) => DftEvent::Open(first_child),
None => DftEvent::Close(id),
})
}
DftEvent::Close(id) => {
let neighbors = hier
.neighbors(id)
.expect("[consistency] the node being traversed must be alive");
Some(match neighbors.next_sibling() {
Some(next_sibling) => DftEvent::Open(next_sibling),
None => {
let parent = neighbors.parent().expect(
"[consistency] parent node must exist since the node is not the root",
);
DftEvent::Close(parent)
}
})
}
}
}
fn next_of_next_backward(&mut self, hier: &Hierarchy<Id>) -> Option<DftEvent<Id>> {
let (next, next_back) = self.next?;
if next == next_back {
return None;
}
match next_back {
DftEvent::Close(id) => {
let neighbors = hier
.neighbors(id)
.expect("[consistency] the node being traversed must be alive");
Some(match neighbors.last_child(hier) {
Some(last_child) => DftEvent::Close(last_child),
None => DftEvent::Open(id),
})
}
DftEvent::Open(id) => {
let neighbors = hier
.neighbors(id)
.expect("[consistency] the node being traversed must be alive");
Some(match neighbors.prev_sibling(hier) {
Some(prev_sibling) => DftEvent::Close(prev_sibling),
None => {
let parent = neighbors.parent().expect(
"[consistency] parent node must exist since the node is not the root",
);
DftEvent::Open(parent)
}
})
}
}
}
#[must_use]
pub(crate) fn peek(&self) -> Option<DftEvent<Id>> {
self.next.map(|(forward, _back)| forward)
}
#[must_use]
pub(crate) fn peek_back(&self) -> Option<DftEvent<Id>> {
self.next.map(|(_fwd, back)| back)
}
}
#[derive(Debug, Clone, Copy)]
pub struct AncestorsTraverser<Id> {
next: Option<Id>,
}
impl<Id: InternalNodeId> AncestorsTraverser<Id> {
#[inline]
#[must_use]
pub(crate) fn with_start(id: Id, hier: &Hierarchy<Id>) -> Self {
if !hier.is_alive(id) {
panic!("[precondition] the node to be traversed must be alive");
}
Self { next: Some(id) }
}
#[must_use]
pub(crate) fn next(&mut self, hier: &Hierarchy<Id>) -> Option<Id> {
let next = self.next?;
self.next = hier
.neighbors(next)
.expect("[consistency] the node being traversed must be alive")
.parent();
Some(next)
}
#[inline]
#[must_use]
pub(crate) fn peek(&self) -> Option<Id> {
self.next
}
}
#[derive(Debug, Clone, Copy)]
pub struct SiblingsTraverser<Id> {
next: Option<(Id, Id)>,
}
impl<Id: InternalNodeId> SiblingsTraverser<Id> {
#[inline]
#[must_use]
pub(crate) fn with_parent(parent: Id, hier: &Hierarchy<Id>) -> Self {
let neighbors = hier
.neighbors(parent)
.expect("[precondition] the node being traversed must be alive");
let next = neighbors.first_last_child(hier);
Self { next }
}
#[inline]
#[must_use]
pub(crate) fn with_first_sibling(first: Id, hier: &Hierarchy<Id>) -> Self {
let parent = hier
.neighbors(first)
.expect("[precondition] the node being traversed must be alive")
.parent();
let last = parent
.and_then(|parent| hier.neighbors(parent))
.map_or(first, |neighbors| {
neighbors
.last_child(hier)
.expect("[consistency] the parent must have children `first`")
});
Self {
next: Some((first, last)),
}
}
#[inline]
#[must_use]
pub(crate) fn with_last_sibling(last: Id, hier: &Hierarchy<Id>) -> Self {
let parent = hier
.neighbors(last)
.expect("[precondition] the node being traversed must be alive")
.parent();
let first = parent
.and_then(|parent| hier.neighbors(parent))
.map_or(last, |neighbors| {
neighbors
.first_child()
.expect("[consistency] the parent must have children `last`")
});
Self {
next: Some((first, last)),
}
}
pub(crate) fn next(&mut self, hier: &Hierarchy<Id>) -> Option<Id> {
let (next, next_back) = self.next?;
match self.next_of_next_forward(hier) {
Some(next_of_next) => {
self.next = Some((next_of_next, next_back));
}
None => {
self.next = None;
}
}
Some(next)
}
pub(crate) fn next_back(&mut self, hier: &Hierarchy<Id>) -> Option<Id> {
let (next, next_back) = self.next?;
match self.next_of_next_backward(hier) {
Some(next_of_next_back) => {
self.next = Some((next, next_of_next_back));
}
None => {
self.next = None;
}
}
Some(next_back)
}
fn next_of_next_forward(&mut self, hier: &Hierarchy<Id>) -> Option<Id> {
let (next, next_back) = self.next?;
if next == next_back {
return None;
}
let neighbors = hier
.neighbors(next)
.expect("[consistency] the node being traversed must be alive");
neighbors.next_sibling()
}
fn next_of_next_backward(&mut self, hier: &Hierarchy<Id>) -> Option<Id> {
let (next, next_back) = self.next?;
if next == next_back {
return None;
}
let neighbors = hier
.neighbors(next_back)
.expect("[consistency] the node being traversed must be alive");
neighbors.prev_sibling(hier)
}
#[must_use]
pub(crate) fn peek(&self) -> Option<Id> {
self.next.map(|(forward, _back)| forward)
}
#[must_use]
pub(crate) fn peek_back(&self) -> Option<Id> {
self.next.map(|(_fwd, back)| back)
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct SafeModeDepthFirstTraverser<Id> {
next: Option<DftEvent<Id>>,
root: Id,
}
impl<Id: InternalNodeId> SafeModeDepthFirstTraverser<Id> {
#[must_use]
pub(crate) fn new(root: Id, hier: &Hierarchy<Id>) -> Self {
if !hier.is_alive(root) {
panic!("[precondition] the node to be traversed must be alive");
}
Self {
next: Some(DftEvent::Open(root)),
root,
}
}
pub(crate) fn next(&mut self, hier: &Hierarchy<Id>) -> Option<DftEvent<Id>> {
let next = self.next?;
self.next = self.next_of_next(hier);
Some(next)
}
fn next_of_next(&mut self, hier: &Hierarchy<Id>) -> Option<DftEvent<Id>> {
let next = self.next?;
if next == DftEvent::Close(self.root) {
return None;
}
let next_of_next = match next {
DftEvent::Open(id) => {
let neighbors = hier
.neighbors(id)
.expect("[consistency] the current node must be alive");
match neighbors.first_child() {
Some(first_child) => DftEvent::Open(first_child),
None => DftEvent::Close(id),
}
}
DftEvent::Close(id) => {
let neighbors = hier
.neighbors(id)
.expect("[consistency] the current node must be alive");
match neighbors.next_sibling() {
Some(next_sibling) => DftEvent::Open(next_sibling),
None => {
debug_assert_ne!(
id, self.root,
"[consistency] closing of the root must have been handled specially"
);
let parent = neighbors.parent().expect(
"[consistency] parent node must exist since the node is not the root",
);
DftEvent::Close(parent)
}
}
}
};
Some(next_of_next)
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct ShallowDepthFirstTraverser<Id> {
#[allow(clippy::type_complexity)]
next: Option<((DftEvent<Id>, usize), (DftEvent<Id>, usize))>,
max_depth: Option<NonMaxUsize>,
}
impl<Id: InternalNodeId> ShallowDepthFirstTraverser<Id> {
#[must_use]
pub(crate) fn with_toplevel_and_max_depth(
id: Id,
hier: &Hierarchy<Id>,
max_depth: Option<usize>,
) -> Self {
if !hier.is_alive(id) {
panic!("[precondition] the node to be traversed must be alive");
}
let max_depth = max_depth.and_then(NonMaxUsize::new);
Self {
next: Some(((DftEvent::Open(id), 0), (DftEvent::Close(id), 0))),
max_depth,
}
}
#[inline]
#[must_use]
pub(crate) fn max_depth(&self) -> Option<usize> {
self.max_depth.map(|v| v.get())
}
pub(crate) fn next(&mut self, hier: &Hierarchy<Id>) -> Option<(DftEvent<Id>, usize)> {
let (next, next_back) = self.next?;
match self.next_of_next_forward(hier) {
Some(next_of_next) => {
self.next = Some((next_of_next, next_back));
}
None => {
self.next = None;
}
}
Some(next)
}
pub(crate) fn next_back(&mut self, hier: &Hierarchy<Id>) -> Option<(DftEvent<Id>, usize)> {
let (next, next_back) = self.next?;
match self.next_of_next_backward(hier) {
Some(next_of_next_back) => {
self.next = Some((next, next_of_next_back));
}
None => {
self.next = None;
}
}
Some(next_back)
}
fn next_of_next_forward(&mut self, hier: &Hierarchy<Id>) -> Option<(DftEvent<Id>, usize)> {
let (next, next_back) = self.next?;
if next == next_back {
return None;
}
let (next, next_depth) = next;
match next {
DftEvent::Open(id) => {
if Some(next_depth) == self.max_depth() {
return Some((DftEvent::Close(id), next_depth));
}
let neighbors = hier
.neighbors(id)
.expect("[consistency] the node being traversed must be alive");
Some(match neighbors.first_child() {
Some(first_child) => (DftEvent::Open(first_child), next_depth + 1),
None => (DftEvent::Close(id), next_depth),
})
}
DftEvent::Close(id) => {
let neighbors = hier
.neighbors(id)
.expect("[consistency] the node being traversed must be alive");
Some(match neighbors.next_sibling() {
Some(next_sibling) => (DftEvent::Open(next_sibling), next_depth),
None => {
let parent = neighbors.parent().expect(
"[consistency] parent node must exist since the node is not the root",
);
(DftEvent::Close(parent), next_depth - 1)
}
})
}
}
}
fn next_of_next_backward(&mut self, hier: &Hierarchy<Id>) -> Option<(DftEvent<Id>, usize)> {
let (next, next_back) = self.next?;
if next == next_back {
return None;
}
let (next_back, next_depth) = next_back;
match next_back {
DftEvent::Close(id) => {
if Some(next_depth) == self.max_depth() {
return Some((DftEvent::Open(id), next_depth));
}
let neighbors = hier
.neighbors(id)
.expect("[consistency] the node being traversed must be alive");
Some(match neighbors.last_child(hier) {
Some(last_child) => (DftEvent::Close(last_child), next_depth + 1),
None => (DftEvent::Open(id), next_depth),
})
}
DftEvent::Open(id) => {
let neighbors = hier
.neighbors(id)
.expect("[consistency] the node being traversed must be alive");
Some(match neighbors.prev_sibling(hier) {
Some(prev_sibling) => (DftEvent::Close(prev_sibling), next_depth),
None => {
let parent = neighbors.parent().expect(
"[consistency] parent node must exist since the node is not the root",
);
(DftEvent::Open(parent), next_depth - 1)
}
})
}
}
}
#[must_use]
pub(crate) fn peek(&self) -> Option<(DftEvent<Id>, usize)> {
self.next.map(|(forward, _back)| forward)
}
#[must_use]
pub(crate) fn peek_back(&self) -> Option<(DftEvent<Id>, usize)> {
self.next.map(|(_fwd, back)| back)
}
}
#[derive(Debug, Clone, Copy)]
pub(crate) struct BreadthFirstTraverser<Id> {
inner: ShallowDepthFirstTraverser<Id>,
root: Option<Id>,
current_depth: usize,
}
impl<Id: InternalNodeId> BreadthFirstTraverser<Id> {
#[must_use]
pub(crate) fn with_toplevel(id: Id, hier: &Hierarchy<Id>) -> Self {
if !hier.is_alive(id) {
panic!("[precondition] the node to be traversed must be alive");
}
Self {
inner: ShallowDepthFirstTraverser::with_toplevel_and_max_depth(id, hier, Some(0)),
root: Some(id),
current_depth: 0,
}
}
pub(crate) fn next(&mut self, hier: &Hierarchy<Id>) -> Option<(Id, usize)> {
let root = self.root?;
if let Some(id) = self.next_inner(hier) {
return Some((id, self.current_depth));
}
self.current_depth += 1;
self.inner = ShallowDepthFirstTraverser::with_toplevel_and_max_depth(
root,
hier,
Some(self.current_depth),
);
if let Some(id) = self.next_inner(hier) {
return Some((id, self.current_depth));
}
self.root = None;
None
}
fn next_inner(&mut self, hier: &Hierarchy<Id>) -> Option<Id> {
while let Some((ev, depth)) = self.inner.next(hier) {
if depth == self.current_depth {
if let DftEvent::Open(id) = ev {
return Some(id);
}
}
}
None
}
}
#[derive(Debug, Clone, Copy)]
enum BftQueuedEvent<Id> {
Node(Id),
IncrementDepth,
}
#[derive(Debug, Clone)]
pub(crate) struct AllocatingBreadthFirstTraverser<Id> {
events: VecDeque<BftQueuedEvent<Id>>,
current_depth: usize,
}
impl<Id: InternalNodeId> AllocatingBreadthFirstTraverser<Id> {
#[must_use]
pub(crate) fn with_toplevel(id: Id, hier: &Hierarchy<Id>) -> Self {
if !hier.is_alive(id) {
panic!("[precondition] the node to be traversed must be alive");
}
let mut events = VecDeque::new();
events.push_back(BftQueuedEvent::Node(id));
events.push_back(BftQueuedEvent::IncrementDepth);
Self {
events,
current_depth: 0,
}
}
pub(crate) fn next(&mut self, hier: &Hierarchy<Id>) -> Option<(Id, usize)> {
while let Some(ev) = self.events.pop_front() {
let next = match ev {
BftQueuedEvent::Node(v) => v,
BftQueuedEvent::IncrementDepth => {
if self.events.is_empty() {
self.events = Default::default();
return None;
}
self.current_depth += 1;
self.events.push_back(BftQueuedEvent::IncrementDepth);
continue;
}
};
{
let mut next_child = hier
.neighbors(next)
.expect("[consistency] the node to be traversed must be alive")
.first_child();
while let Some(child) = next_child {
self.events.push_back(BftQueuedEvent::Node(child));
next_child = hier
.neighbors(child)
.expect("[consistency] the node to be traversed must be alive")
.next_sibling();
}
}
return Some((next, self.current_depth));
}
None
}
pub(crate) fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.events.len();
if len <= 1 {
(0, Some(0))
} else {
(len - 1, None)
}
}
#[inline]
#[must_use]
pub(crate) fn peek(&self) -> Option<(Id, usize)> {
match *self.events.front()? {
BftQueuedEvent::Node(next) => Some((next, self.current_depth)),
BftQueuedEvent::IncrementDepth => match *self.events.get(1)? {
BftQueuedEvent::Node(next) => Some((next, self.current_depth + 1)),
BftQueuedEvent::IncrementDepth => panic!(
"[consistency] `IncrementDepth` must not appear right after `IncrementDepth`"
),
},
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use core::mem;
use crate::dynamic::NodeIdUsize;
#[test]
fn bft_queued_event_niche_optimized() {
assert_eq!(
mem::size_of::<BftQueuedEvent<NodeIdUsize>>(),
mem::size_of::<NodeIdUsize>(),
"`BftQueuedEvent` type must have the same size as \
`NodeId` type due to niche optimization"
);
}
}