use super::*;
impl DependencyGraph {
pub fn add_range_edges(
&mut self,
dependent: VertexId,
ranges: &[SharedRangeRef<'static>],
current_sheet_id: SheetId,
) {
self.add_range_dependent_edges(dependent, ranges, current_sheet_id);
}
pub fn get_range_dependencies(
&self,
vertex: VertexId,
) -> Option<&Vec<SharedRangeRef<'static>>> {
self.formula_to_range_deps.get(&vertex)
}
#[cfg(test)]
pub(crate) fn formula_to_range_deps(
&self,
) -> &FxHashMap<VertexId, Vec<SharedRangeRef<'static>>> {
&self.formula_to_range_deps
}
#[cfg(test)]
pub(crate) fn stripe_to_dependents(&self) -> &FxHashMap<StripeKey, FxHashSet<VertexId>> {
&self.stripe_to_dependents
}
pub(super) fn add_range_dependent_edges(
&mut self,
dependent: VertexId,
ranges: &[SharedRangeRef<'static>],
current_sheet_id: SheetId,
) {
if ranges.is_empty() {
return;
}
self.formula_to_range_deps
.insert(dependent, ranges.to_vec());
for range in ranges {
let sheet_id = match range.sheet {
SharedSheetLocator::Id(id) => id,
_ => current_sheet_id,
};
let s_row = range.start_row.map(|b| b.index);
let e_row = range.end_row.map(|b| b.index);
let s_col = range.start_col.map(|b| b.index);
let e_col = range.end_col.map(|b| b.index);
let col_stripes = (s_row.is_none() && e_row.is_none())
|| (s_col.is_some() && e_col.is_some() && (s_row.is_none() || e_row.is_none()));
let row_stripes = (s_col.is_none() && e_col.is_none())
|| (s_row.is_some() && e_row.is_some() && (s_col.is_none() || e_col.is_none()));
if col_stripes && !row_stripes {
let sc = s_col.unwrap_or(0);
let ec = e_col.unwrap_or(sc);
for col in sc..=ec {
let key = StripeKey {
sheet_id,
stripe_type: StripeType::Column,
index: col,
};
self.stripe_to_dependents
.entry(key.clone())
.or_default()
.insert(dependent);
#[cfg(test)]
{
if self.stripe_to_dependents.get(&key).map(|s| s.len()) == Some(1)
&& let Ok(mut g) = self.instr.lock()
{
g.stripe_inserts += 1;
}
}
}
continue;
}
if row_stripes && !col_stripes {
let sr = s_row.unwrap_or(0);
let er = e_row.unwrap_or(sr);
for row in sr..=er {
let key = StripeKey {
sheet_id,
stripe_type: StripeType::Row,
index: row,
};
self.stripe_to_dependents
.entry(key.clone())
.or_default()
.insert(dependent);
#[cfg(test)]
{
if self.stripe_to_dependents.get(&key).map(|s| s.len()) == Some(1)
&& let Ok(mut g) = self.instr.lock()
{
g.stripe_inserts += 1;
}
}
}
continue;
}
let start_row = s_row.unwrap_or(0);
let start_col = s_col.unwrap_or(0);
let end_row = e_row.unwrap_or(start_row);
let end_col = e_col.unwrap_or(start_col);
let height = end_row.saturating_sub(start_row) + 1;
let width = end_col.saturating_sub(start_col) + 1;
if self.config.enable_block_stripes && height > 1 && width > 1 {
let start_block_row = start_row / BLOCK_H;
let end_block_row = end_row / BLOCK_H;
let start_block_col = start_col / BLOCK_W;
let end_block_col = end_col / BLOCK_W;
for block_row in start_block_row..=end_block_row {
for block_col in start_block_col..=end_block_col {
let key = StripeKey {
sheet_id,
stripe_type: StripeType::Block,
index: block_index(block_row * BLOCK_H, block_col * BLOCK_W),
};
self.stripe_to_dependents
.entry(key.clone())
.or_default()
.insert(dependent);
#[cfg(test)]
{
if self.stripe_to_dependents.get(&key).map(|s| s.len()) == Some(1)
&& let Ok(mut g) = self.instr.lock()
{
g.stripe_inserts += 1;
}
}
}
}
} else if height > width {
for col in start_col..=end_col {
let key = StripeKey {
sheet_id,
stripe_type: StripeType::Column,
index: col,
};
self.stripe_to_dependents
.entry(key.clone())
.or_default()
.insert(dependent);
#[cfg(test)]
{
if self.stripe_to_dependents.get(&key).map(|s| s.len()) == Some(1)
&& let Ok(mut g) = self.instr.lock()
{
g.stripe_inserts += 1;
}
}
}
} else {
for row in start_row..=end_row {
let key = StripeKey {
sheet_id,
stripe_type: StripeType::Row,
index: row,
};
self.stripe_to_dependents
.entry(key.clone())
.or_default()
.insert(dependent);
#[cfg(test)]
{
if self.stripe_to_dependents.get(&key).map(|s| s.len()) == Some(1)
&& let Ok(mut g) = self.instr.lock()
{
g.stripe_inserts += 1;
}
}
}
}
}
}
pub fn add_range_deps_from_keys(
&mut self,
dependent: VertexId,
keys: &[crate::engine::plan::RangeKey],
current_sheet_id: SheetId,
) {
use crate::engine::plan::RangeKey as RK;
if keys.is_empty() {
return;
}
let mut shared_ranges: Vec<SharedRangeRef<'static>> = Vec::with_capacity(keys.len());
for k in keys {
let sheet_loc = SharedSheetLocator::Id(match k {
RK::Rect { sheet, .. }
| RK::WholeRow { sheet, .. }
| RK::WholeCol { sheet, .. }
| RK::OpenRect { sheet, .. } => *sheet,
});
let mk_axis = |idx0: u32| formualizer_common::AxisBound::new(idx0, false);
let built = match k {
RK::Rect { start, end, .. } => {
let sr = mk_axis(start.row());
let sc = mk_axis(start.col());
let er = mk_axis(end.row());
let ec = mk_axis(end.col());
SharedRangeRef::from_parts(sheet_loc, Some(sr), Some(sc), Some(er), Some(ec))
.ok()
}
RK::WholeRow { row, .. } => {
let r0 = row.saturating_sub(1);
let b = mk_axis(r0);
SharedRangeRef::from_parts(sheet_loc, Some(b), None, Some(b), None).ok()
}
RK::WholeCol { col, .. } => {
let c0 = col.saturating_sub(1);
let b = mk_axis(c0);
SharedRangeRef::from_parts(sheet_loc, None, Some(b), None, Some(b)).ok()
}
RK::OpenRect { start, end, .. } => {
let (sr, sc) = match start {
Some(p) => (Some(mk_axis(p.row())), Some(mk_axis(p.col()))),
None => (None, None),
};
let (er, ec) = match end {
Some(p) => (Some(mk_axis(p.row())), Some(mk_axis(p.col()))),
None => (None, None),
};
SharedRangeRef::from_parts(sheet_loc, sr, sc, er, ec).ok()
}
};
if let Some(r) = built {
shared_ranges.push(r.into_owned());
}
}
if shared_ranges.is_empty() {
return;
}
self.formula_to_range_deps
.insert(dependent, shared_ranges.clone());
for range in &shared_ranges {
let sheet_id = match range.sheet {
SharedSheetLocator::Id(id) => id,
_ => current_sheet_id,
};
let s_row = range.start_row.map(|b| b.index);
let e_row = range.end_row.map(|b| b.index);
let s_col = range.start_col.map(|b| b.index);
let e_col = range.end_col.map(|b| b.index);
let col_stripes = (s_row.is_none() && e_row.is_none())
|| (s_col.is_some() && e_col.is_some() && (s_row.is_none() || e_row.is_none()));
let row_stripes = (s_col.is_none() && e_col.is_none())
|| (s_row.is_some() && e_row.is_some() && (s_col.is_none() || e_col.is_none()));
if col_stripes && !row_stripes {
let sc = s_col.unwrap_or(0);
let ec = e_col.unwrap_or(sc);
for col in sc..=ec {
let key = StripeKey {
sheet_id,
stripe_type: StripeType::Column,
index: col,
};
self.stripe_to_dependents
.entry(key)
.or_default()
.insert(dependent);
}
continue;
}
if row_stripes && !col_stripes {
let sr = s_row.unwrap_or(0);
let er = e_row.unwrap_or(sr);
for row in sr..=er {
let key = StripeKey {
sheet_id,
stripe_type: StripeType::Row,
index: row,
};
self.stripe_to_dependents
.entry(key)
.or_default()
.insert(dependent);
}
continue;
}
let start_row = s_row.unwrap_or(0);
let start_col = s_col.unwrap_or(0);
let end_row = e_row.unwrap_or(start_row);
let end_col = e_col.unwrap_or(start_col);
let height = end_row.saturating_sub(start_row) + 1;
let width = end_col.saturating_sub(start_col) + 1;
if self.config.enable_block_stripes && height > 1 && width > 1 {
let start_block_row = start_row / BLOCK_H;
let end_block_row = end_row / BLOCK_H;
let start_block_col = start_col / BLOCK_W;
let end_block_col = end_col / BLOCK_W;
for block_row in start_block_row..=end_block_row {
for block_col in start_block_col..=end_block_col {
let key = StripeKey {
sheet_id,
stripe_type: StripeType::Block,
index: block_index(block_row * BLOCK_H, block_col * BLOCK_W),
};
self.stripe_to_dependents
.entry(key)
.or_default()
.insert(dependent);
}
}
} else if height > width {
for col in start_col..=end_col {
let key = StripeKey {
sheet_id,
stripe_type: StripeType::Column,
index: col,
};
self.stripe_to_dependents
.entry(key)
.or_default()
.insert(dependent);
}
} else {
for row in start_row..=end_row {
let key = StripeKey {
sheet_id,
stripe_type: StripeType::Row,
index: row,
};
self.stripe_to_dependents
.entry(key)
.or_default()
.insert(dependent);
}
}
}
}
}