use super::Cell;
#[derive(Debug, Default)]
pub struct CellStore {
cells: Vec<Cell>,
rows: Vec<(i32, usize, usize)>,
sorted: bool,
}
impl CellStore {
pub fn push(&mut self, cell: Cell) {
self.cells.push(cell);
self.sorted = false;
}
pub fn is_empty(&self) -> bool {
self.cells.is_empty()
}
pub fn clear(&mut self) {
self.cells.clear();
self.rows.clear();
self.sorted = false;
}
pub fn sort(&mut self) {
if self.sorted {
return;
}
self.cells.sort_unstable_by_key(|c| (c.y, c.x));
self.rows.clear();
let mut start = 0usize;
while start < self.cells.len() {
let Some(first) = self.cells.get(start) else {
break;
};
let y = first.y;
let mut end = start + 1;
while self.cells.get(end).is_some_and(|c| c.y == y) {
end += 1;
}
self.rows.push((y, start, end));
start = end;
}
self.sorted = true;
}
pub fn rows(&self) -> impl Iterator<Item = (i32, &[Cell])> {
let cells = &self.cells;
let rows: &[(i32, usize, usize)] = if self.sorted { &self.rows } else { &[] };
rows.iter()
.filter_map(move |&(y, start, end)| cells.get(start..end).map(|row| (y, row)))
}
}
#[cfg(test)]
mod tests {
use super::*;
fn cell(x: i32, y: i32) -> Cell {
Cell {
x,
y,
cover: 1,
area: 1,
}
}
#[test]
fn rows_come_out_sorted_and_grouped() {
let mut store = CellStore::default();
store.push(cell(3, 1));
store.push(cell(1, 0));
store.push(cell(2, 1));
store.push(cell(0, 0));
store.sort();
let rows: Vec<(i32, Vec<i32>)> = store
.rows()
.map(|(y, cells)| (y, cells.iter().map(|c| c.x).collect()))
.collect();
assert_eq!(rows, vec![(0, vec![0, 1]), (1, vec![2, 3])]);
}
#[test]
fn an_unsorted_store_yields_no_rows() {
let mut store = CellStore::default();
store.push(cell(0, 0));
assert_eq!(store.rows().count(), 0, "sort() is the gate");
store.sort();
assert_eq!(store.rows().count(), 1);
}
#[test]
fn clearing_resets_the_sorted_flag() {
let mut store = CellStore::default();
store.push(cell(0, 0));
store.sort();
store.clear();
assert!(store.is_empty());
assert_eq!(store.rows().count(), 0);
}
#[test]
fn negative_rows_sort_before_positive_ones() {
let mut store = CellStore::default();
store.push(cell(0, 5));
store.push(cell(0, -3));
store.sort();
let ys: Vec<i32> = store.rows().map(|(y, _)| y).collect();
assert_eq!(ys, vec![-3, 5]);
}
}