use super::EdgesIterable;
#[derive(Clone, Copy)]
pub struct EdgesToNodesIterator<'a, const N: usize, NI> {
row1: [&'a NI; N],
row2: [&'a NI; N],
i: usize,
j: usize,
back_i: usize,
back_j: usize,
last_index: usize,
back_i_underflow: bool,
back_j_underflow: bool,
}
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum EdgeNodeError {
EmptyEdges,
NotEnoughCapacity,
}
impl<'a, const N: usize, NI> EdgesToNodesIterator<'a, N, NI>
where
NI: Ord,
{
pub fn new<E>(edges: &'a E) -> Result<Self, EdgeNodeError>
where
E: EdgesIterable<Node = NI> + 'a,
{
let first_ref = edges.iter_edges().next();
if first_ref.is_none() {
return Err(EdgeNodeError::EmptyEdges);
}
let init = first_ref.unwrap().0;
let mut row1: [&'a NI; N] = core::array::from_fn(|_| init);
let mut row2: [&'a NI; N] = core::array::from_fn(|_| init);
let mut len = 0;
for (index, edge) in edges.iter_edges().enumerate() {
if index == N {
return Err(EdgeNodeError::NotEnoughCapacity);
}
row1[index] = edge.0;
row2[index] = edge.1;
len = index;
}
len += 1;
let sort_1 = &mut row1[..len];
let sort_2 = &mut row2[..len];
sort_1.sort_unstable();
sort_2.sort_unstable();
Ok(Self {
row1,
row2,
i: 0,
j: 0,
last_index: len - 1,
back_i: len - 1,
back_j: len - 1,
back_i_underflow: false,
back_j_underflow: false,
})
}
}
impl<'a, const N: usize, NI> Iterator for EdgesToNodesIterator<'a, N, NI>
where
NI: PartialEq + Ord,
{
type Item = &'a NI;
fn next(&mut self) -> Option<Self::Item> {
while self.i <= self.back_i || self.j <= self.back_j {
let prev_i = self.i;
let prev_j = self.j;
if prev_i <= self.back_i
&& (prev_j.wrapping_sub(1) == self.back_j || self.row1[prev_i] < self.row2[prev_j])
{
self.i += 1;
if prev_i == 0 || self.row1[prev_i] != self.row1[prev_i - 1] {
return Some(self.row1[prev_i]);
}
} else if prev_j <= self.back_j
&& (prev_i.wrapping_sub(1) == self.back_i || self.row2[prev_j] < self.row1[prev_i])
{
self.j += 1;
if prev_j == 0 || self.row2[prev_j] != self.row2[prev_j - 1] {
return Some(self.row2[prev_j]);
}
} else {
self.i += 1;
self.j += 1;
if (prev_i == 0 || self.row1[prev_i] != self.row1[prev_i - 1])
&& (prev_j == 0 || self.row2[prev_j] != self.row2[prev_j - 1])
{
return Some(self.row1[prev_i]);
}
}
}
None
}
}
impl<const N: usize, NI> DoubleEndedIterator for EdgesToNodesIterator<'_, N, NI>
where
NI: PartialEq + Ord,
{
fn next_back(&mut self) -> Option<Self::Item> {
while (self.back_i >= self.i && !self.back_i_underflow)
|| (self.back_j >= self.j && !self.back_j_underflow)
{
let prev_i_underflow = self.back_i_underflow;
let prev_j_underflow = self.back_j_underflow;
let prev_i = self.back_i;
let prev_j = self.back_j;
if (prev_i >= self.i && !prev_i_underflow)
&& (prev_j.wrapping_add(1) == self.j || self.row1[prev_i] > self.row2[prev_j])
{
let (new_back, new_underflow) = self.back_i.overflowing_sub(1);
self.back_i = new_back;
self.back_i_underflow = new_underflow;
if prev_i == self.last_index || self.row1[prev_i] != self.row1[prev_i + 1] {
return Some(self.row1[prev_i]);
}
} else if (prev_j >= self.j && !prev_j_underflow)
&& (prev_i.wrapping_add(1) == self.i || self.row2[prev_j] > self.row1[prev_i])
{
let (new_back, new_underflow) = self.back_j.overflowing_sub(1);
self.back_j = new_back;
self.back_j_underflow = new_underflow;
if prev_j == self.last_index || self.row2[prev_j] != self.row2[prev_j + 1] {
return Some(self.row2[prev_j]);
}
} else {
let (new_back, new_underflow) = self.back_i.overflowing_sub(1);
self.back_i = new_back;
self.back_i_underflow = new_underflow;
let (new_back, new_underflow) = self.back_j.overflowing_sub(1);
self.back_j = new_back;
self.back_j_underflow = new_underflow;
if (prev_i == self.last_index
|| (!prev_i_underflow && (self.row1[prev_i] != self.row1[prev_i + 1])))
&& (prev_j == self.last_index
|| (!prev_j_underflow && (self.row2[prev_j] != self.row2[prev_j + 1])))
{
return Some(self.row1[prev_i]);
}
}
}
None
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::edges::{EdgeStruct, EdgeStructOption};
fn test_node_collect<'a, const C: usize, E, NI>(
edges: &'a E,
cmp: Result<&[&NI], EdgeNodeError>,
) where
E: EdgesIterable<Node = NI> + 'a,
NI: Ord + Default + core::fmt::Debug + 'a,
{
let default = NI::default();
let mut collect: [&NI; 256] = core::array::from_fn(|_| &default);
let mut last_index = 0;
let result = EdgesToNodesIterator::<C, _>::new(edges);
if let Ok(edge_to_nodes) = result {
for (idx, node) in edge_to_nodes.zip(collect.iter_mut()).enumerate() {
*node.1 = node.0;
last_index = idx
}
let final_slice = &collect[..last_index + 1];
assert_eq!(final_slice, cmp.unwrap());
} else {
assert_eq!(result.err(), cmp.err());
}
}
fn test_node_collect_back<'a, const C: usize, E, NI>(
edges: &'a E,
cmp: Result<&[&NI], EdgeNodeError>,
) where
E: EdgesIterable<Node = NI> + 'a,
NI: Ord + Default + core::fmt::Debug + 'a,
{
let default = NI::default();
let mut collect: [&NI; 256] = core::array::from_fn(|_| &default);
let mut last_index = 0;
let result = EdgesToNodesIterator::<C, _>::new(edges);
if let Ok(mut edge_to_nodes) = result {
while let Some(node) = edge_to_nodes.next_back() {
collect[last_index] = node;
last_index += 1;
}
let final_slice = &collect[..last_index];
if let Ok(expected) = cmp {
let mut collect_rev: [&NI; 256] = core::array::from_fn(|_| &default);
let expected_reversed = &mut collect_rev[..expected.len()];
expected_reversed.clone_from_slice(expected);
expected_reversed.reverse();
assert_eq!(final_slice, expected_reversed);
} else {
panic!("Expected an error, but got Ok");
}
} else {
assert_eq!(result.err(), cmp.err());
}
}
#[test]
fn test_corner_cases() {
let edges = EdgeStructOption::<0, usize>([]);
test_node_collect::<1, _, _>(&edges, Err(EdgeNodeError::EmptyEdges));
test_node_collect::<0, _, _>(&edges, Err(EdgeNodeError::EmptyEdges));
let edges = EdgeStruct([(1, 1)]);
test_node_collect::<0, _, _>(&edges, Err(EdgeNodeError::NotEnoughCapacity));
test_node_collect::<1, _, _>(&edges, Ok(&[&1]));
let edges = EdgeStruct([(1, 1), (1, 1)]);
test_node_collect::<0, _, _>(&edges, Err(EdgeNodeError::NotEnoughCapacity));
test_node_collect::<1, _, _>(&edges, Err(EdgeNodeError::NotEnoughCapacity));
test_node_collect::<2, _, _>(&edges, Ok(&[&1]));
test_node_collect::<3, _, _>(&edges, Ok(&[&1]));
test_node_collect::<2, _, _>(&EdgeStruct([(2, 1), (1, 2)]), Ok(&[&1, &2]));
}
#[test]
fn test_corner_cases_backward() {
let edges = EdgeStructOption::<0, usize>([]);
test_node_collect_back::<1, _, _>(&edges, Err(EdgeNodeError::EmptyEdges));
test_node_collect_back::<0, _, _>(&edges, Err(EdgeNodeError::EmptyEdges));
let edges = EdgeStruct([(1, 1)]);
test_node_collect_back::<0, _, _>(&edges, Err(EdgeNodeError::NotEnoughCapacity));
test_node_collect_back::<1, _, _>(&edges, Ok(&[&1]));
let edges = EdgeStruct([(1, 1), (1, 1)]);
test_node_collect_back::<0, _, _>(&edges, Err(EdgeNodeError::NotEnoughCapacity));
test_node_collect_back::<1, _, _>(&edges, Err(EdgeNodeError::NotEnoughCapacity));
test_node_collect_back::<2, _, _>(&edges, Ok(&[&1]));
test_node_collect_back::<3, _, _>(&edges, Ok(&[&1]));
test_node_collect_back::<2, _, _>(&EdgeStruct([(2, 1), (1, 2)]), Ok(&[&1, &2]));
}
#[test]
fn test_simple_sequence() {
let edges = EdgeStructOption::<4, usize>([Some((0, 1)), Some((1, 20)), None, Some((2, 3))]);
test_node_collect::<5, _, _>(&edges, Ok(&[&0, &1, &2, &3, &20]));
test_node_collect::<3, _, _>(&edges, Ok(&[&0, &1, &2, &3, &20]));
test_node_collect::<2, _, _>(&edges, Err(EdgeNodeError::NotEnoughCapacity))
}
#[test]
fn test_simple_sequence_backward() {
let edges = EdgeStructOption::<4, usize>([Some((0, 1)), Some((1, 20)), None, Some((2, 3))]);
test_node_collect_back::<5, _, _>(&edges, Ok(&[&0, &1, &2, &3, &20]));
test_node_collect_back::<3, _, _>(&edges, Ok(&[&0, &1, &2, &3, &20]));
test_node_collect_back::<2, _, _>(&edges, Err(EdgeNodeError::NotEnoughCapacity));
}
#[test]
fn test_option_structs() {
let edges = EdgeStructOption::<4, usize>([Some((0, 1)), Some((1, 20)), None, Some((2, 3))]);
test_node_collect::<5, _, _>(&edges, Ok(&[&0, &1, &2, &3, &20]));
}
#[test]
fn test_unsorted_edges() {
let edges = EdgeStruct([(10, 1), (3, 5), (7, 2), (4, 6), (2, 8), (9, 0)]);
test_node_collect::<12, _, _>(&edges, Ok(&[&0, &1, &2, &3, &4, &5, &6, &7, &8, &9, &10]));
}
#[test]
fn test_unsorted_edges_backward() {
let edges = EdgeStruct([(10, 1), (3, 5), (7, 2), (4, 6), (2, 8), (9, 0)]);
test_node_collect_back::<12, _, _>(
&edges,
Ok(&[&0, &1, &2, &3, &4, &5, &6, &7, &8, &9, &10]),
);
}
#[test]
fn test_multiple_edges_with_duplicates() {
let edges = EdgeStruct([
(3, 4),
(1, 2),
(2, 3),
(1, 4),
(2, 2),
(4, 5),
(3, 3),
(5, 6),
(5, 5),
]);
test_node_collect::<10, _, _>(&edges, Ok(&[&1, &2, &3, &4, &5, &6]));
}
#[test]
fn test_multiple_edges_with_duplicates_backward() {
let edges = EdgeStruct([
(3, 4),
(1, 2),
(2, 3),
(1, 4),
(2, 2),
(4, 5),
(3, 3),
(5, 6),
(5, 5),
]);
test_node_collect_back::<10, _, _>(&edges, Ok(&[&1, &2, &3, &4, &5, &6]));
}
#[test]
fn test_forward_and_backward_iteration() {
let edges = EdgeStruct([(1, 3), (2, 4), (5, 7), (6, 8)]);
let mut iterator =
EdgesToNodesIterator::<8, _>::new(&edges).expect("Failed to create iterator");
assert_eq!(iterator.next(), Some(&1));
assert_eq!(iterator.next_back(), Some(&8));
assert_eq!(iterator.next(), Some(&2));
assert_eq!(iterator.next_back(), Some(&7));
assert_eq!(iterator.next(), Some(&3));
assert_eq!(iterator.next_back(), Some(&6));
assert_eq!(iterator.next(), Some(&4));
assert_eq!(iterator.next_back(), Some(&5));
assert_eq!(iterator.next(), None);
assert_eq!(iterator.next_back(), None);
}
}