use crate::{CellIndex, Direction, Resolution, index::bits};
use core::iter::FusedIterator;
pub struct Children {
parent_resolution: Resolution,
target_resolution: Resolution,
scratchpad: u64,
skip_count: i16,
count: u64,
}
impl Children {
pub fn new(index: CellIndex, resolution: Resolution) -> Self {
Self {
parent_resolution: index.resolution(),
target_resolution: resolution,
scratchpad: get_starting_state(index, resolution),
skip_count: if index.is_pentagon() {
i16::from(u8::from(resolution))
} else {
-1
},
count: index.children_count(resolution),
}
}
fn next_direction(&mut self, resolution: Resolution) -> u8 {
let one = 1 << resolution.direction_offset();
self.scratchpad += one;
bits::get_direction(self.scratchpad, resolution)
}
}
impl Iterator for Children {
type Item = CellIndex;
fn next(&mut self) -> Option<CellIndex> {
if self.count == 0 {
return None;
}
let index = CellIndex::new_unchecked(self.scratchpad);
self.count -= 1;
if self.count != 0 {
for resolution in Resolution::range(
self.parent_resolution,
self.target_resolution,
)
.rev()
{
let direction = self.next_direction(resolution);
if self.skip_count == i16::from(resolution)
&& direction == u8::from(Direction::K)
{
self.next_direction(resolution);
self.skip_count -= 1;
}
if direction > crate::direction::MAX {
self.scratchpad =
bits::clr_direction(self.scratchpad, resolution);
continue;
}
break;
}
}
Some(index)
}
fn size_hint(&self) -> (usize, Option<usize>) {
let count = usize::try_from(self.count).unwrap_or(usize::MAX);
(count, Some(count))
}
}
impl ExactSizeIterator for Children {}
impl FusedIterator for Children {}
fn get_starting_state(index: CellIndex, resolution: Resolution) -> u64 {
let parent_resolution = index.resolution();
let range =
usize::from(resolution).saturating_sub(parent_resolution.into());
let mut scratchpad = u64::from(index);
if range != 0 {
let mask = (1 << (range * h3o_bit::DIRECTION_BITSIZE)) - 1;
let offset = resolution.direction_offset();
scratchpad &= !(mask << offset);
scratchpad = bits::set_resolution(scratchpad, resolution);
}
scratchpad
}
#[cfg(test)]
#[path = "./children_tests.rs"]
mod tests;