formualizer_eval/
broadcast.rs1use formualizer_common::{ExcelError, ExcelErrorKind};
2
3pub type Shape2D = (usize, usize);
4
5pub fn broadcast_shape(shapes: &[Shape2D]) -> Result<Shape2D, ExcelError> {
6 if shapes.is_empty() {
7 return Ok((1, 1));
8 }
9 let mut rows = 1usize;
10 let mut cols = 1usize;
11 for &(r, c) in shapes {
12 rows = broadcast_dim(rows, r)?;
13 cols = broadcast_dim(cols, c)?;
14 }
15 Ok((rows, cols))
16}
17
18fn broadcast_dim(a: usize, b: usize) -> Result<usize, ExcelError> {
19 if a == b || a == 1 {
20 return Ok(b.max(a));
21 }
22 if b == 1 {
23 return Ok(a.max(b));
24 }
25 Err(ExcelError::new(ExcelErrorKind::Value).with_message(format!(
26 "Incompatible dimensions for broadcasting: {a} vs {b}"
27 )))
28}
29
30#[inline]
31pub fn project_index(idx: (usize, usize), shape: Shape2D) -> (usize, usize) {
32 let (r, c) = shape;
33 let rr = if r == 1 { 0 } else { idx.0 };
34 let cc = if c == 1 { 0 } else { idx.1 };
35 (rr, cc)
36}