From b5828411ac05f57627ae7c8650a487fe40aa7a69 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Wed, 28 Aug 2024 08:45:54 -0700 Subject: [PATCH] work --- rust/pspp/src/output/pivot/mod.rs | 76 +++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 4 deletions(-) diff --git a/rust/pspp/src/output/pivot/mod.rs b/rust/pspp/src/output/pivot/mod.rs index d8f5c9f17f..394d01537e 100644 --- a/rust/pspp/src/output/pivot/mod.rs +++ b/rust/pspp/src/output/pivot/mod.rs @@ -142,18 +142,58 @@ pub enum Axis3 { /// An axis within a pivot table. #[derive(Default)] -pub struct TableAxis { +pub struct Axis { /// `dimensions[0]` is the innermost dimension. dimensions: Vec, /// The number of rows or columns along the axis, that is, the product of - /// `dimensions[*].n_leaves`. It is 0 if any dimension has 0 leaves. + /// `dimensions[*].len()`. It is 0 if any dimension has 0 leaves. extent: usize, /// Sum of `dimensions[*].label_depth`. label_depth: usize, } +pub struct AxisCursor<'a> { + axis: &'a Axis, + indexes: Vec, +} + +impl<'a> AxisCursor<'a> { + fn next(&'a mut self) -> Option<&'a Vec> { + if self.indexes.is_empty() { + if self + .axis + .dimensions + .iter() + .any(|dimension| dimension.is_empty()) + { + return None; + } + self.indexes = vec![0; self.axis.dimensions.len()]; + Some(&self.indexes) + } else { + for (index, dimension) in self.indexes.iter_mut().zip(self.axis.dimensions.iter()) { + *index += 1; + if *index < dimension.len() { + return Some(&self.indexes); + }; + *index = 0 + } + None + } + } +} + +impl Axis { + fn cursor(&self) -> AxisCursor { + AxisCursor { + axis: self, + indexes: Vec::new(), + } + } +} + /// Dimensions. /// /// A [Dimension] identifies the categories associated with a single dimension @@ -201,6 +241,16 @@ pub struct Dimension { label_depth: usize, } +impl Dimension { + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + pub fn len(&self) -> usize { + self.data_leaves.len() + } +} + pub struct Group { name: Value, label_depth: usize, @@ -590,8 +640,8 @@ pub struct Table { caption: Option, notes: Option, dimensions: Vec, - axes: EnumMap, - cells: HashMap, + axes: EnumMap, + cells: HashMap, } impl Table { @@ -629,6 +679,24 @@ impl Table { cells: HashMap::new(), } } + + fn cell_index(&self, data_indexes: &[usize]) -> usize { + debug_assert_eq!(data_indexes.len(), self.dimensions.len()); + let mut index = 0; + for (dimension, data_index) in self.dimensions.iter().zip(data_indexes.iter()) { + debug_assert!(*data_index < dimension.len()); + index = dimension.len() * index + data_index; + } + index + } + + fn insert(&mut self, data_indexes: &[usize], value: Value) { + self.cells.insert(self.cell_index(data_indexes), value); + } + + fn get(&self, data_indexes: &[usize]) -> Option<&Value> { + self.cells.get(&self.cell_index(data_indexes)) + } } /// Whether to show variable or value labels or the underlying value or variable name. -- 2.30.2