use crate::bits::Bits;
use crate::word::Word;
pub fn block_starts<W: Word>(rows: &[W], w: u32, h: u32, out: &mut [W]) {
assert_eq!(rows.len(), out.len(), "block_starts: out must match rows");
debug_assert!(
(1..=W::BITS).contains(&w) && h >= 1,
"block {w}×{h} out of range"
);
out.copy_from_slice(rows);
let len = rows.len();
let mut n = h as usize;
while n > 1 {
let s = n >> 1;
for r in 0..len.saturating_sub(s) {
out[r] = out[r].and(out[r + s]);
}
for cell in out.iter_mut().skip(len.saturating_sub(s)) {
*cell = W::ZERO;
}
n -= s;
}
if h as usize > len {
for cell in out.iter_mut() {
*cell = W::ZERO;
}
}
for cell in out.iter_mut() {
*cell = cell.run_starts(w);
}
}
#[must_use]
pub fn find_block<W: Word>(rows: &[W], w: u32, h: u32, scratch: &mut [W]) -> Option<(usize, u32)> {
block_starts(rows, w, h, scratch);
scratch
.iter()
.enumerate()
.find_map(|(r, &row)| row.first_set().map(|c| (r, c)))
}
pub fn set_block<W: Word>(rows: &mut [W], row: usize, col: u32, w: u32, h: u32, set: bool) {
debug_assert!(
col + w <= W::BITS && row + h as usize <= rows.len(),
"block outside grid"
);
let mask = W::low_ones(w).shl(col);
for cell in &mut rows[row..row + h as usize] {
*cell = if set {
cell.or(mask)
} else {
cell.and(mask.not())
};
}
}