Use ndarray for 2-d arrays.
authorBen Pfaff <blp@cs.stanford.edu>
Fri, 4 Apr 2025 20:34:59 +0000 (13:34 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Fri, 4 Apr 2025 20:34:59 +0000 (13:34 -0700)
rust/Cargo.lock
rust/pspp/Cargo.toml
rust/pspp/src/output/table.rs

index e7ff05b88e00d69b11ff024e396d2e38c93572fe..62a1ba22478b039c250a1aceb752ae141b6a107b 100644 (file)
@@ -741,6 +741,16 @@ dependencies = [
  "url",
 ]
 
+[[package]]
+name = "matrixmultiply"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9380b911e3e96d10c1f415da0876389aaf1b56759054eeb0de7df940c456ba1a"
+dependencies = [
+ "autocfg",
+ "rawpointer",
+]
+
 [[package]]
 name = "memchr"
 version = "2.7.4"
@@ -768,6 +778,21 @@ dependencies = [
  "windows-sys 0.52.0",
 ]
 
+[[package]]
+name = "ndarray"
+version = "0.16.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "882ed72dce9365842bf196bdeedf5055305f11fc8c03dee7bb0194a6cad34841"
+dependencies = [
+ "matrixmultiply",
+ "num-complex",
+ "num-integer",
+ "num-traits",
+ "portable-atomic",
+ "portable-atomic-util",
+ "rawpointer",
+]
+
 [[package]]
 name = "num"
 version = "0.4.3"
@@ -943,6 +968,21 @@ version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
 
+[[package]]
+name = "portable-atomic"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e"
+
+[[package]]
+name = "portable-atomic-util"
+version = "0.2.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
+dependencies = [
+ "portable-atomic",
+]
+
 [[package]]
 name = "ppv-lite86"
 version = "0.2.21"
@@ -987,6 +1027,7 @@ dependencies = [
  "lazy_static",
  "libc",
  "libm",
+ "ndarray",
  "num",
  "num-derive",
  "num-traits",
@@ -1080,6 +1121,12 @@ dependencies = [
  "getrandom",
 ]
 
+[[package]]
+name = "rawpointer"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3"
+
 [[package]]
 name = "redox_syscall"
 version = "0.5.3"
index 4b1015b2126b7da6cbe9750893fcd76a64c6b843..9fc4a923f03f9474776212f268ebc055d8e7ce02 100644 (file)
@@ -40,6 +40,7 @@ quick-xml = { version = "0.37.2", features = ["serialize"] }
 serde = { version = "1.0.218", features = ["derive"] }
 color = { version = "0.2.3", features = ["serde"] }
 binrw = "0.14.1"
+ndarray = "0.16.1"
 
 [target.'cfg(windows)'.dependencies]
 windows-sys = { version = "0.48.0", features = ["Win32_Globalization"] }
index 8e913607c0014a367cc3e9cc1a94edce45a462c3..6b9ef5f66a54266b08aaf7b1b95a21cd8ff19ffa 100644 (file)
@@ -13,6 +13,7 @@
 use std::{ops::Range, sync::Arc};
 
 use enum_map::{enum_map, EnumMap};
+use ndarray::{Array, Array2};
 
 use crate::output::pivot::Coord2;
 
@@ -173,7 +174,7 @@ pub struct Table {
     /// Table header rows and columns.
     pub h: Coord2,
 
-    pub contents: Vec<Content>,
+    pub contents: Array2<Content>,
 
     /// Styles for areas of the table.
     pub areas: EnumMap<Area, AreaStyle>,
@@ -182,7 +183,7 @@ pub struct Table {
     pub borders: EnumMap<Border, BorderStyle>,
 
     /// Horizontal and vertical rules.
-    pub rules: EnumMap<Axis2, Vec<Border>>,
+    pub rules: EnumMap<Axis2, Array2<Border>>,
 
     /// How to present values.
     pub value_options: ValueOptions,
@@ -199,51 +200,37 @@ impl Table {
         Self {
             n,
             h: headers,
-            contents: vec![Content::default(); n.y() * n.x()],
+            contents: Array::default((n.x(), n.y())),
             areas,
             borders,
             rules: enum_map! {
-                Axis2::X => vec![Border::Title; (n.y() + 1) * n.x()],
-                Axis2::Y => vec![Border::Title; n.y() * (n.x() + 1)],
+                Axis2::X => Array::from_elem((n.x(), n.y() + 1), Border::Title),
+                Axis2::Y => Array::from_elem((n.x() + 1, n.y()), Border::Title),
             },
             value_options,
         }
     }
 
-    pub fn offset(&self, pos: Coord2) -> usize {
-        pos.x() + self.n.x() * pos.y()
-    }
-
     pub fn get(&self, coord: Coord2) -> CellRef<'_> {
         CellRef {
             coord,
-            content: &self.contents[self.offset(coord)],
+            content: &self.contents[[coord.x(), coord.y()]],
         }
     }
 
     pub fn get_rule(&self, axis: Axis2, pos: Coord2) -> BorderStyle {
-        debug_assert!(pos.x() < self.n[Axis2::X] + (axis == Axis2::X) as usize);
-        debug_assert!(pos.y() < self.n[Axis2::Y] + (axis == Axis2::Y) as usize);
-
-        let border = if axis == Axis2::Y {
-            self.rules[axis][pos.x() + self.n.x() * pos.y()]
-        } else {
-            self.rules[axis][pos.x() + (self.n.x() + 1) * pos.y()]
-        };
-        self.borders[border]
+        self.borders[self.rules[axis][[pos.x(), pos.y()]]]
     }
 
     pub fn put(&mut self, region: Rect2, inner: CellInner) {
         use Axis2::*;
         if region[X].len() == 1 && region[Y].len() == 1 {
-            let offset = self.offset(Coord2::new(region[X].start, region[Y].start));
-            self.contents[offset] = Content::Value(inner);
+            self.contents[[region[X].start, region[Y].start]] = Content::Value(inner);
         } else {
             let cell = Arc::new(Cell::new(inner, region.clone()));
             for y in region[Y].clone() {
                 for x in region[X].clone() {
-                    let offset = self.offset(Coord2::new(x, y));
-                    self.contents[offset] = Content::Join(cell.clone())
+                    self.contents[[x, y]] = Content::Join(cell.clone())
                 }
             }
         }
@@ -254,7 +241,7 @@ impl Table {
         debug_assert!(x.start <= x.end);
         debug_assert!(x.end <= self.n.x());
         for x in x {
-            self.rules[Axis2::X][x + self.n.x() * y] = border;
+            self.rules[Axis2::X][[x, y]] = border;
         }
     }
 
@@ -263,7 +250,7 @@ impl Table {
         debug_assert!(y.start <= y.end);
         debug_assert!(y.end <= self.n.y());
         for y in y {
-            self.rules[Axis2::Y][x + (self.n.x() + 1) * y] = border;
+            self.rules[Axis2::Y][[x, y]] = border;
         }
     }