formualizer_eval/engine/graph/
range_deps.rs1use super::*;
2
3impl DependencyGraph {
4 pub fn add_range_edges(
6 &mut self,
7 dependent: VertexId,
8 ranges: &[SharedRangeRef<'static>],
9 current_sheet_id: SheetId,
10 ) {
11 self.add_range_dependent_edges(dependent, ranges, current_sheet_id);
12 }
13
14 pub fn get_range_dependencies(
18 &self,
19 vertex: VertexId,
20 ) -> Option<&Vec<SharedRangeRef<'static>>> {
21 self.formula_to_range_deps.get(&vertex)
22 }
23
24 #[cfg(test)]
25 pub(crate) fn formula_to_range_deps(
26 &self,
27 ) -> &FxHashMap<VertexId, Vec<SharedRangeRef<'static>>> {
28 &self.formula_to_range_deps
29 }
30
31 #[cfg(test)]
32 pub(crate) fn stripe_to_dependents(&self) -> &FxHashMap<StripeKey, FxHashSet<VertexId>> {
33 &self.stripe_to_dependents
34 }
35
36 pub(super) fn add_range_dependent_edges(
37 &mut self,
38 dependent: VertexId,
39 ranges: &[SharedRangeRef<'static>],
40 current_sheet_id: SheetId,
41 ) {
42 if ranges.is_empty() {
43 return;
44 }
45
46 self.formula_to_range_deps
47 .insert(dependent, ranges.to_vec());
48
49 for range in ranges {
50 let sheet_id = match range.sheet {
51 SharedSheetLocator::Id(id) => id,
52 _ => current_sheet_id,
53 };
54
55 let s_row = range.start_row.map(|b| b.index);
56 let e_row = range.end_row.map(|b| b.index);
57 let s_col = range.start_col.map(|b| b.index);
58 let e_col = range.end_col.map(|b| b.index);
59
60 let col_stripes = (s_row.is_none() && e_row.is_none())
61 || (s_col.is_some() && e_col.is_some() && (s_row.is_none() || e_row.is_none()));
62 let row_stripes = (s_col.is_none() && e_col.is_none())
63 || (s_row.is_some() && e_row.is_some() && (s_col.is_none() || e_col.is_none()));
64
65 if col_stripes && !row_stripes {
66 let sc = s_col.unwrap_or(0);
67 let ec = e_col.unwrap_or(sc);
68 for col in sc..=ec {
69 let key = StripeKey {
70 sheet_id,
71 stripe_type: StripeType::Column,
72 index: col,
73 };
74 self.stripe_to_dependents
75 .entry(key.clone())
76 .or_default()
77 .insert(dependent);
78 #[cfg(test)]
79 {
80 if self.stripe_to_dependents.get(&key).map(|s| s.len()) == Some(1) {
81 self.instr.stripe_inserts += 1;
82 }
83 }
84 }
85 continue;
86 }
87
88 if row_stripes && !col_stripes {
89 let sr = s_row.unwrap_or(0);
90 let er = e_row.unwrap_or(sr);
91 for row in sr..=er {
92 let key = StripeKey {
93 sheet_id,
94 stripe_type: StripeType::Row,
95 index: row,
96 };
97 self.stripe_to_dependents
98 .entry(key.clone())
99 .or_default()
100 .insert(dependent);
101 #[cfg(test)]
102 {
103 if self.stripe_to_dependents.get(&key).map(|s| s.len()) == Some(1) {
104 self.instr.stripe_inserts += 1;
105 }
106 }
107 }
108 continue;
109 }
110
111 let start_row = s_row.unwrap_or(0);
112 let start_col = s_col.unwrap_or(0);
113 let end_row = e_row.unwrap_or(start_row);
114 let end_col = e_col.unwrap_or(start_col);
115
116 let height = end_row.saturating_sub(start_row) + 1;
117 let width = end_col.saturating_sub(start_col) + 1;
118
119 if self.config.enable_block_stripes && height > 1 && width > 1 {
120 let start_block_row = start_row / BLOCK_H;
121 let end_block_row = end_row / BLOCK_H;
122 let start_block_col = start_col / BLOCK_W;
123 let end_block_col = end_col / BLOCK_W;
124
125 for block_row in start_block_row..=end_block_row {
126 for block_col in start_block_col..=end_block_col {
127 let key = StripeKey {
128 sheet_id,
129 stripe_type: StripeType::Block,
130 index: block_index(block_row * BLOCK_H, block_col * BLOCK_W),
131 };
132 self.stripe_to_dependents
133 .entry(key.clone())
134 .or_default()
135 .insert(dependent);
136 #[cfg(test)]
137 {
138 if self.stripe_to_dependents.get(&key).map(|s| s.len()) == Some(1) {
139 self.instr.stripe_inserts += 1;
140 }
141 }
142 }
143 }
144 } else if height > width {
145 for col in start_col..=end_col {
146 let key = StripeKey {
147 sheet_id,
148 stripe_type: StripeType::Column,
149 index: col,
150 };
151 self.stripe_to_dependents
152 .entry(key.clone())
153 .or_default()
154 .insert(dependent);
155 #[cfg(test)]
156 {
157 if self.stripe_to_dependents.get(&key).map(|s| s.len()) == Some(1) {
158 self.instr.stripe_inserts += 1;
159 }
160 }
161 }
162 } else {
163 for row in start_row..=end_row {
164 let key = StripeKey {
165 sheet_id,
166 stripe_type: StripeType::Row,
167 index: row,
168 };
169 self.stripe_to_dependents
170 .entry(key.clone())
171 .or_default()
172 .insert(dependent);
173 #[cfg(test)]
174 {
175 if self.stripe_to_dependents.get(&key).map(|s| s.len()) == Some(1) {
176 self.instr.stripe_inserts += 1;
177 }
178 }
179 }
180 }
181 }
182 }
183
184 pub fn add_range_deps_from_keys(
186 &mut self,
187 dependent: VertexId,
188 keys: &[crate::engine::plan::RangeKey],
189 current_sheet_id: SheetId,
190 ) {
191 use crate::engine::plan::RangeKey as RK;
192 if keys.is_empty() {
193 return;
194 }
195
196 let mut shared_ranges: Vec<SharedRangeRef<'static>> = Vec::with_capacity(keys.len());
197 for k in keys {
198 let sheet_loc = SharedSheetLocator::Id(match k {
199 RK::Rect { sheet, .. }
200 | RK::WholeRow { sheet, .. }
201 | RK::WholeCol { sheet, .. }
202 | RK::OpenRect { sheet, .. } => *sheet,
203 });
204
205 let mk_axis = |idx0: u32| formualizer_common::AxisBound::new(idx0, false);
206
207 let built = match k {
208 RK::Rect { start, end, .. } => {
209 let sr = mk_axis(start.row());
210 let sc = mk_axis(start.col());
211 let er = mk_axis(end.row());
212 let ec = mk_axis(end.col());
213 SharedRangeRef::from_parts(sheet_loc, Some(sr), Some(sc), Some(er), Some(ec))
214 .ok()
215 }
216 RK::WholeRow { row, .. } => {
217 let r0 = row.saturating_sub(1);
218 let b = mk_axis(r0);
219 SharedRangeRef::from_parts(sheet_loc, Some(b), None, Some(b), None).ok()
220 }
221 RK::WholeCol { col, .. } => {
222 let c0 = col.saturating_sub(1);
223 let b = mk_axis(c0);
224 SharedRangeRef::from_parts(sheet_loc, None, Some(b), None, Some(b)).ok()
225 }
226 RK::OpenRect { start, end, .. } => {
227 let (sr, sc) = match start {
228 Some(p) => (Some(mk_axis(p.row())), Some(mk_axis(p.col()))),
229 None => (None, None),
230 };
231 let (er, ec) = match end {
232 Some(p) => (Some(mk_axis(p.row())), Some(mk_axis(p.col()))),
233 None => (None, None),
234 };
235 SharedRangeRef::from_parts(sheet_loc, sr, sc, er, ec).ok()
236 }
237 };
238
239 if let Some(r) = built {
240 shared_ranges.push(r.into_owned());
241 }
242 }
243
244 if shared_ranges.is_empty() {
245 return;
246 }
247
248 self.formula_to_range_deps
249 .insert(dependent, shared_ranges.clone());
250
251 for range in &shared_ranges {
252 let sheet_id = match range.sheet {
253 SharedSheetLocator::Id(id) => id,
254 _ => current_sheet_id,
255 };
256
257 let s_row = range.start_row.map(|b| b.index);
258 let e_row = range.end_row.map(|b| b.index);
259 let s_col = range.start_col.map(|b| b.index);
260 let e_col = range.end_col.map(|b| b.index);
261
262 let col_stripes = (s_row.is_none() && e_row.is_none())
263 || (s_col.is_some() && e_col.is_some() && (s_row.is_none() || e_row.is_none()));
264 let row_stripes = (s_col.is_none() && e_col.is_none())
265 || (s_row.is_some() && e_row.is_some() && (s_col.is_none() || e_col.is_none()));
266
267 if col_stripes && !row_stripes {
268 let sc = s_col.unwrap_or(0);
269 let ec = e_col.unwrap_or(sc);
270 for col in sc..=ec {
271 let key = StripeKey {
272 sheet_id,
273 stripe_type: StripeType::Column,
274 index: col,
275 };
276 self.stripe_to_dependents
277 .entry(key)
278 .or_default()
279 .insert(dependent);
280 }
281 continue;
282 }
283
284 if row_stripes && !col_stripes {
285 let sr = s_row.unwrap_or(0);
286 let er = e_row.unwrap_or(sr);
287 for row in sr..=er {
288 let key = StripeKey {
289 sheet_id,
290 stripe_type: StripeType::Row,
291 index: row,
292 };
293 self.stripe_to_dependents
294 .entry(key)
295 .or_default()
296 .insert(dependent);
297 }
298 continue;
299 }
300
301 let start_row = s_row.unwrap_or(0);
302 let start_col = s_col.unwrap_or(0);
303 let end_row = e_row.unwrap_or(start_row);
304 let end_col = e_col.unwrap_or(start_col);
305
306 let height = end_row.saturating_sub(start_row) + 1;
307 let width = end_col.saturating_sub(start_col) + 1;
308
309 if self.config.enable_block_stripes && height > 1 && width > 1 {
310 let start_block_row = start_row / BLOCK_H;
311 let end_block_row = end_row / BLOCK_H;
312 let start_block_col = start_col / BLOCK_W;
313 let end_block_col = end_col / BLOCK_W;
314
315 for block_row in start_block_row..=end_block_row {
316 for block_col in start_block_col..=end_block_col {
317 let key = StripeKey {
318 sheet_id,
319 stripe_type: StripeType::Block,
320 index: block_index(block_row * BLOCK_H, block_col * BLOCK_W),
321 };
322 self.stripe_to_dependents
323 .entry(key)
324 .or_default()
325 .insert(dependent);
326 }
327 }
328 } else if height > width {
329 for col in start_col..=end_col {
330 let key = StripeKey {
331 sheet_id,
332 stripe_type: StripeType::Column,
333 index: col,
334 };
335 self.stripe_to_dependents
336 .entry(key)
337 .or_default()
338 .insert(dependent);
339 }
340 } else {
341 for row in start_row..=end_row {
342 let key = StripeKey {
343 sheet_id,
344 stripe_type: StripeType::Row,
345 index: row,
346 };
347 self.stripe_to_dependents
348 .entry(key)
349 .or_default()
350 .insert(dependent);
351 }
352 }
353 }
354 }
355}