Convert a sparse tile to a dense tile by materialising every cell. Cells absent in the sparse payload become [`CellValue::Null`]. The caller is responsible for the integer-only-dim precondition (dense indexing relies on integer cell offsets) — this is enforced because non-`Int64`/`TimestampMs` dims do not have well-defined `tile_extent` semantics in dense layout.
(tile: &SparseTile, schema: &ArraySchema)
| 35 | /// because non-`Int64`/`TimestampMs` dims do not have well-defined |
| 36 | /// `tile_extent` semantics in dense layout. |
| 37 | pub fn sparse_to_dense(tile: &SparseTile, schema: &ArraySchema) -> ArrayResult<DenseTile> { |
| 38 | use crate::schema::dim_spec::DimType; |
| 39 | use crate::types::coord::value::CoordValue; |
| 40 | for d in &schema.dims { |
| 41 | if !matches!(d.dtype, DimType::Int64 | DimType::TimestampMs) { |
| 42 | return Err(ArrayError::InvalidSchema { |
| 43 | array: schema.name.clone(), |
| 44 | detail: format!( |
| 45 | "dense promotion requires integer dims; '{}' is {:?}", |
| 46 | d.name, d.dtype |
| 47 | ), |
| 48 | }); |
| 49 | } |
| 50 | } |
| 51 | let mut dense = DenseTile::empty(schema); |
| 52 | let mut mbr = MbrBuilder::new(schema.arity(), schema.attrs.len()); |
| 53 | let n_rows = tile.nnz() as usize; |
| 54 | for row in 0..n_rows { |
| 55 | // Reconstruct row's coord from the dim dictionaries. |
| 56 | let coord: Vec<CoordValue> = schema |
| 57 | .dims |
| 58 | .iter() |
| 59 | .enumerate() |
| 60 | .map(|(i, _)| { |
| 61 | let dict = &tile.dim_dicts[i]; |
| 62 | let idx = dict.indices[row] as usize; |
| 63 | dict.values[idx].clone() |
| 64 | }) |
| 65 | .collect(); |
| 66 | let attrs: Vec<CellValue> = (0..schema.attrs.len()) |
| 67 | .map(|i| tile.attr_cols[i][row].clone()) |
| 68 | .collect(); |
| 69 | let flat = flat_index_for_coord(schema, &coord)?; |
| 70 | for (i, a) in attrs.iter().enumerate() { |
| 71 | dense.attr_cols[i][flat] = a.clone(); |
| 72 | } |
| 73 | mbr.fold(&coord, &attrs); |
| 74 | } |
| 75 | dense.mbr = mbr.build(); |
| 76 | Ok(dense) |
| 77 | } |
| 78 | |
| 79 | /// Row-major flat index `((c0 - lo0) * extent1 * extent2 ...) + ...`. |
| 80 | fn flat_index_for_coord( |