use crate::Cell;
use std::collections::VecDeque;
pub struct CumulativeHeightCache {
row_heights: Vec<f32>,
prefix_sums: Vec<f32>,
dirty: bool,
}
impl CumulativeHeightCache {
pub fn new() -> Self {
Self {
row_heights: Vec::new(),
prefix_sums: Vec::new(),
dirty: true,
}
}
pub fn set_heights(&mut self, heights: Vec<f32>) {
self.row_heights = heights;
self.dirty = true;
}
pub fn set_uniform_height(&mut self, row_count: usize, height: f32) {
self.row_heights = vec![height; row_count];
self.dirty = true;
}
pub fn mark_dirty(&mut self) {
self.dirty = true;
}
fn rebuild(&mut self) {
let n = self.row_heights.len();
self.prefix_sums = Vec::with_capacity(n + 1);
self.prefix_sums.push(0.0_f32);
let mut acc = 0.0_f32;
for &h in &self.row_heights {
acc += h;
self.prefix_sums.push(acc);
}
self.dirty = false;
}
fn ensure_built(&mut self) {
if self.dirty {
self.rebuild();
}
}
pub fn row_at_offset(&mut self, y: f32) -> usize {
self.ensure_built();
if self.prefix_sums.is_empty() {
return 0;
}
let idx = self.prefix_sums.partition_point(|&ps| ps <= y);
let max_row = self.row_heights.len().saturating_sub(1);
idx.saturating_sub(1).min(max_row)
}
pub fn row_y_range(&mut self, row: usize) -> (f32, f32) {
self.ensure_built();
let start = self.prefix_sums.get(row).copied().unwrap_or(0.0);
let end = self.prefix_sums.get(row + 1).copied().unwrap_or(start);
(start, end)
}
pub fn visible_range(
&mut self,
viewport_y: f32,
viewport_height: f32,
) -> std::ops::Range<usize> {
self.ensure_built();
let start = self.row_at_offset(viewport_y);
let end_y = viewport_y + viewport_height;
let end_row = self.row_at_offset(end_y);
let end = (end_row + 1).min(self.row_heights.len());
start..end
}
pub fn total_height(&mut self) -> f32 {
self.ensure_built();
self.prefix_sums.last().copied().unwrap_or(0.0)
}
pub fn row_count(&self) -> usize {
self.row_heights.len()
}
}
impl Default for CumulativeHeightCache {
fn default() -> Self {
Self::new()
}
}
pub struct RowCache {
data: VecDeque<(usize, Vec<Cell>)>,
max: usize,
}
impl RowCache {
pub fn new(max: usize) -> Self {
Self {
data: VecDeque::new(),
max,
}
}
pub fn get(&self, index: usize) -> Option<&Vec<Cell>> {
self.data
.iter()
.find(|(i, _)| *i == index)
.map(|(_, cells)| cells)
}
pub fn insert(&mut self, index: usize, cells: Vec<Cell>) {
if self.max == 0 {
return;
}
self.data.retain(|(i, _)| *i != index);
if self.data.len() >= self.max {
self.data.pop_front();
}
self.data.push_back((index, cells));
}
pub fn invalidate(&mut self) {
self.data.clear();
}
pub fn len(&self) -> usize {
self.data.len()
}
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
}