From a4311812a852f40e8bd7eaeae399f5f7b356ae6e Mon Sep 17 00:00:00 2001 From: Alexandre Bonnetain Date: Wed, 2 Aug 2023 00:36:14 +0200 Subject: [PATCH] --wip-- [skip ci] --- src/lib.rs | 1750 ++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 1339 insertions(+), 411 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index cdcbc66..eea18c7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,33 +1,41 @@ #![warn(clippy::all, clippy::pedantic)] - +// TODO: Update documentation /*! # Two Dimensional Grid Continuous growable 2D data structure. The purpose of this crate is to provide an universal data structure that is faster, uses less memory, and is easier to use than a naive `Vec>` solution. -Similar to *C-like* arrays `grid` uses a flat 1D `Vec` data structure to have a continuous -memory data layout. See also [this](https://stackoverflow.com/questions/17259877/1d-or-2d-array-whats-faster) -explanation of why you should probably use a one-dimensional array approach. - -Note that this crate uses a [*row-major*](https://eli.thegreenplace.net/2015/memory-layout-of-multi-dimensional-arrays) memory layout. -Therefore, `grid.push_row()` is way faster then the `grid.push_col()` operation. - This crate will always provide a 2D data structure. If you need three or more dimensions take a look at the [ndarray](https://docs.rs/ndarray/0.13.0/ndarray/) library. The `grid` create is a container for all kind of data. If you need to perform matrix operations, you are better of with a linear algebra lib, such as [cgmath](https://docs.rs/cgmath/0.17.0/cgmath/) or [nalgebra](https://docs.rs/nalgebra/0.21.0/nalgebra/). No other dependencies except for the std lib are used. Most of the functions `std::Vec` offer are also implemented in `grid` and slightly modified for a 2D data object. + +# Memory layout + +Similar to *C-like* arrays, `grid` uses a flat 1D `Vec` data structure to have a continuous +memory data layout. See also [this](https://stackoverflow.com/questions/17259877/1d-or-2d-array-whats-faster) +explanation of why you should probably use a one-dimensional array approach. + +Note that this crate uses a [*row-major*](https://eli.thegreenplace.net/2015/memory-layout-of-multi-dimensional-arrays) memory layout by default. + +If you need a specific memory layout, please seek the `*_with_order` constructors. You should also take note that some transformation methods +change the internal memory layout, like [`transpose`](Grid::transpose). + +This choice is important, because operations on rows are faster with a row-major memory layout. +Likewise, operations on columns are faster with column-major memory layout. + # Examples ``` use grid::*; let mut grid = grid![[1,2,3] [4,5,6]]; assert_eq!(grid, Grid::from_vec(vec![1,2,3,4,5,6],3)); -assert_eq!(grid.get(0,2), Some(&3)); -assert_eq!(grid[1][1], 5); -assert_eq!(grid.size(), (2,3)); +assert_eq!(grid.get(0, 2), Some(&3)); +assert_eq!(grid[(1, 1)], 5); +assert_eq!(grid.size(), (2, 3)); grid.push_row(vec![7,8,9]); assert_eq!(grid, grid![[1,2,3][4,5,6][7,8,9]]) ``` @@ -41,8 +49,8 @@ extern crate alloc; use alloc::{format, vec, vec::Vec}; #[cfg(feature = "serde")] use serde::{ - ser::{Serialize, Serializer, SerializeStruct}, - de::{self, Deserialize, Deserializer, Visitor, SeqAccess, MapAccess} + de::{self, Deserialize, Deserializer, MapAccess, SeqAccess, Visitor}, + ser::{Serialize, SerializeStruct, Serializer}, }; use core::cmp; @@ -120,6 +128,87 @@ macro_rules! grid { }; } +/// Init a column-major grid with values. +/// +/// Each array within `[]` represents a row starting from top to button. +/// +/// # Examples +/// +/// In this example a grid of numbers from 1 to 9 is created: +/// +/// ``` +/// use grid::grid2; +/// let grid = grid2![[1, 2, 3] +/// [4, 5, 6] +/// [7, 8, 9]]; +/// assert_eq!(grid.size(), (3, 3)); +/// assert_eq!(grid[(1, 1)], 5); +/// ``` +/// +/// # Examples +/// +/// Not that each row must be of the same length. The following example will not compile: +/// +/// ``` ignore +/// use grid::grid2; +/// let grid = grid2![[1, 2, 3] +/// [4, 5] // This does not work! +/// [7, 8, 9]]; +/// ``` +#[macro_export] +macro_rules! grid2 { + () => { + $crate::Grid::from_vec_with_order(vec![], 0, $crate::Order::ColumnMajor) + }; + ( [$( $x:expr ),* ]) => { { + let vec = vec![$($x),*]; + let len = vec.len(); + $crate::Grid::from_vec_with_order(vec, len, $crate::Order::ColumnMajor) + } }; + ( [$( $x0:expr ),*] $([$( $x:expr ),*])* ) => { + { + let mut _assert_width0 = [(); $crate::count!($($x0)*)]; + let cols = $crate::count!($($x0)*); + let rows = 1usize; + + $( + let _assert_width = [(); $crate::count!($($x)*)]; + _assert_width0 = _assert_width; + let rows = rows + 1usize; + )* + + let vec = Vec::with_capacity(rows.checked_mul(cols).unwrap()); + let mut grid = $crate::Grid::from_vec_with_order(vec, cols, $crate::Order::ColumnMajor); + + grid.push_row(vec![$($x0),*]); + $( grid.push_row(vec![$($x),*]); )* + + grid + } + }; +} + +/// Define the internal memory layout of the grid. +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum Order { + /// The data is ordered row by row. + #[default] + RowMajor, + + /// The data is ordered column by column. + ColumnMajor, +} + +impl Order { + fn counterpart(self) -> Self { + match self { + Self::RowMajor => Self::ColumnMajor, + Self::ColumnMajor => Self::RowMajor, + } + } +} + /// Stores elements of a certain type in a 2D grid structure. /// /// Uses a rust `Vec` type to reference the grid data on the heap. @@ -132,11 +221,11 @@ pub struct Grid { data: Vec, cols: usize, rows: usize, + order: Order, } #[cfg(feature = "serde")] impl<'de, T: Deserialize<'de>> Deserialize<'de> for Grid { - fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, @@ -144,7 +233,11 @@ impl<'de, T: Deserialize<'de>> Deserialize<'de> for Grid { use std::marker::PhantomData; #[derive(serde::Deserialize)] #[serde(field_identifier, rename_all = "lowercase")] - enum Field { Data, Cols } + enum Field { + Data, + Cols, + Order, + } struct GridVisitor { _p: PhantomData, @@ -161,11 +254,14 @@ impl<'de, T: Deserialize<'de>> Deserialize<'de> for Grid { where V: SeqAccess<'de>, { - let cols = seq.next_element()? + let cols = seq + .next_element()? .ok_or_else(|| de::Error::invalid_length(0, &self))?; - let data = seq.next_element()? + let data = seq + .next_element()? .ok_or_else(|| de::Error::invalid_length(1, &self))?; - Ok(Grid::from_vec(data, cols)) + let order = seq.next_element()?.unwrap_or_default(); + Ok(Grid::from_vec_with_order(data, cols, order)) } fn visit_map(self, mut map: V) -> Result, V::Error> @@ -174,6 +270,7 @@ impl<'de, T: Deserialize<'de>> Deserialize<'de> for Grid { { let mut cols = None; let mut data = None; + let mut order = None; while let Some(key) = map.next_key()? { match key { Field::Data => { @@ -188,16 +285,23 @@ impl<'de, T: Deserialize<'de>> Deserialize<'de> for Grid { } cols = Some(map.next_value()?); } + Field::Order => { + if order.is_some() { + return Err(de::Error::duplicate_field("order")); + } + order = Some(map.next_value()?); + } } } let cols = cols.ok_or_else(|| de::Error::missing_field("cols"))?; let data = data.ok_or_else(|| de::Error::missing_field("data"))?; - Ok(Grid::from_vec(data, cols)) + let order = order.unwrap_or_default(); + Ok(Grid::from_vec_with_order(data, cols, order)) } } - const FIELDS: &'static [&'static str] = &["cols", "data"]; - deserializer.deserialize_struct("Grid", FIELDS, GridVisitor{ _p: PhantomData}) + const FIELDS: &'static [&'static str] = &["cols", "data", "order"]; + deserializer.deserialize_struct("Grid", FIELDS, GridVisitor { _p: PhantomData }) } } @@ -211,6 +315,7 @@ impl Serialize for Grid { let mut state = serializer.serialize_struct("Grid", 3)?; state.serialize_field("cols", &self.cols)?; state.serialize_field("data", &self.data)?; + state.serialize_field("order", &self.order)?; state.end() } } @@ -222,57 +327,101 @@ impl Grid { /// ``` /// use grid::Grid; /// let grid : Grid = Grid::new(2,3); - /// assert_eq!(grid[0][0], 0); + /// assert_eq!(grid[(0, 0)], 0); /// ``` /// /// If `rows == 0` or `cols == 0` the grid will be empty with no cols and rows. + /// + /// This create a grid with a row-major memory layout. + /// If you need a column-major one, see [`new_with_order`](Grid::new_with_order). + /// + /// # Panics + /// + /// Panics if `rows * cols > usize::MAX`. + #[must_use] + #[inline] + pub fn new(rows: usize, cols: usize) -> Self + where + T: Default, + { + Self::new_with_order(rows, cols, Order::default()) + } + + /// Same as [`new`](Self::new) but with a specific [`Order`]. /// /// # Panics /// - /// Panics if `rows * cols > usize`. - pub fn new(rows: usize, cols: usize) -> Grid + /// Panics if `rows * cols > usize::MAX`. + pub fn new_with_order(rows: usize, cols: usize, order: Order) -> Self where T: Default, { if rows == 0 || cols == 0 { - return Grid { + return Self { data: Vec::new(), rows: 0, cols: 0, + order, }; } let mut data = Vec::new(); data.resize_with(rows.checked_mul(cols).unwrap(), T::default); - Grid { data, cols, rows } + Self { + data, + cols, + rows, + order, + } } /// Init a grid of size rows x columns with the given data element. /// /// If `rows == 0` or `cols == 0` the grid will be empty with no cols and rows. + /// + /// This create a grid with a row-major memory layout. + /// If you need a column-major one, see [`init_with_order`](Grid::init_with_order). + /// + /// # Panics + /// + /// Panics if `rows * cols > usize::MAX`. + #[inline] + pub fn init(rows: usize, cols: usize, data: T) -> Self + where + T: Clone, + { + Self::init_with_order(rows, cols, Order::default(), data) + } + + /// Same as [`init`](Self::init) but with a specific [`Order`]. /// /// # Panics /// - /// Panics if `rows * cols > usize`. - pub fn init(rows: usize, cols: usize, data: T) -> Grid + /// Panics if `rows * cols > usize::MAX`. + pub fn init_with_order(rows: usize, cols: usize, order: Order, data: T) -> Self where T: Clone, { if rows == 0 || cols == 0 { - return Grid { + return Self { data: Vec::new(), rows: 0, cols: 0, + order, }; } - Grid { + Self { data: vec![data; rows.checked_mul(cols).unwrap()], cols, rows, + order, } } /// Returns a grid from a vector with a given column length. /// The length of `vec` must be a multiple of `cols`. + /// + /// This create a grid with a row-major memory layout. + /// If you need a column-major one, see [`from_vec_with_order`](Grid::from_vec_with_order). /// /// For example: /// @@ -297,7 +446,18 @@ impl Grid { /// /// This panics if the vector length isn't a multiple of the number of columns. #[must_use] - pub fn from_vec(vec: Vec, cols: usize) -> Grid { + #[inline] + pub fn from_vec(vec: Vec, cols: usize) -> Self { + Self::from_vec_with_order(vec, cols, Order::default()) + } + + /// Same as [`from_vec`](Self::from_vec) but with a specific [`Order`]. + /// + /// # Panics + /// + /// This panics if the vector length isn't a multiple of the number of columns. + #[must_use] + pub fn from_vec_with_order(vec: Vec, cols: usize, order: Order) -> Self { let rows = vec.len().checked_div(cols).unwrap_or(0); assert_eq!( rows * cols, @@ -311,16 +471,28 @@ impl Grid { data: vec, rows: 0, cols: 0, + order, } } else { Grid { data: vec, rows, cols, + order, } } } + /// Returns the index of the coordinates in the internal vector. + #[inline] + #[must_use] + fn get_index(&self, row: usize, col: usize) -> usize { + match self.order { + Order::RowMajor => row * self.cols + col, + Order::ColumnMajor => col * self.rows + row, + } + } + /// Returns a reference to an element, without performing bound checks. /// Generally not recommended, use with caution! /// @@ -330,7 +502,8 @@ impl Grid { #[inline] #[must_use] pub unsafe fn get_unchecked(&self, row: usize, col: usize) -> &T { - self.data.get_unchecked(row * self.cols + col) + let index = self.get_index(row, col); + self.data.get_unchecked(index) } /// Returns a mutable reference to an element, without performing bound checks. @@ -342,7 +515,8 @@ impl Grid { #[inline] #[must_use] pub unsafe fn get_unchecked_mut(&mut self, row: usize, col: usize) -> &mut T { - self.data.get_unchecked_mut(row * self.cols + col) + let index = self.get_index(row, col); + self.data.get_unchecked_mut(index) } /// Access a certain element in the grid. @@ -386,6 +560,12 @@ impl Grid { self.cols } + /// Returns the internal memory layout of the grid. + #[must_use] + pub fn order(&self) -> &Order { + &self.order + } + /// Returns true if the grid contains no elements. /// For example: /// ``` @@ -399,6 +579,8 @@ impl Grid { } /// Clears the grid. + /// + /// This doesn't change the grid order. pub fn clear(&mut self) { self.rows = 0; self.cols = 0; @@ -406,6 +588,11 @@ impl Grid { } /// Returns an iterator over the whole grid, starting from the first row and column. + /// + /// The iteration order is dependant on the internal memory layout. + /// If you need a specific order, see [`iter_rows`](Grid::iter_rows) or + /// [`iter_cols`](Grid::iter_cols). + /// /// ``` /// use grid::*; /// let grid: Grid = grid![[1,2][3,4]]; @@ -421,6 +608,9 @@ impl Grid { } /// Returns an mutable iterator over the whole grid that allows modifying each value. + /// + /// The iteration order is dependant on the internal memory layout. + /// /// ``` /// use grid::*; /// let mut grid: Grid = grid![[1,2][3,4]]; @@ -450,13 +640,19 @@ impl Grid { /// /// Panics if the col index is out of bounds. pub fn iter_col(&self, col: usize) -> StepBy> { - if col < self.cols { - return self.data[col..].iter().step_by(self.cols); + assert!( + col < self.cols, + "out of bounds. Column must be less than {:?}, but is {:?}", + self.cols, + col + ); + match self.order { + Order::RowMajor => self.data[col..].iter().step_by(self.cols), + Order::ColumnMajor => { + let start = col * self.rows; + self.data[start..(start + self.rows)].iter().step_by(1) + } } - panic!( - "out of bounds. Column must be less than {:?}, but is {:?}.", - self.cols, col - ) } /// Returns a mutable iterator over a column. @@ -470,21 +666,26 @@ impl Grid { /// let next = col_iter.next(); /// assert_eq!(next, Some(&mut 2)); /// *next.unwrap() = 10; - /// assert_eq!(grid[0][1], 10); + /// assert_eq!(grid[(0, 1)], 10); /// ``` /// /// # Panics /// /// Panics if the col index is out of bounds. pub fn iter_col_mut(&mut self, col: usize) -> StepBy> { - let cols = self.cols; - if col < cols { - return self.data[col..].iter_mut().step_by(cols); + assert!( + col < self.cols, + "out of bounds. Column must be less than {:?}, but is {:?}", + self.cols, + col + ); + match self.order { + Order::RowMajor => self.data[col..].iter_mut().step_by(self.cols), + Order::ColumnMajor => { + let start = col * self.rows; + self.data[start..(start + self.rows)].iter_mut().step_by(1) + } } - panic!( - "out of bounds. Column must be less than {:?}, but is {:?}.", - self.cols, col - ) } /// Returns an iterator over a row. @@ -504,15 +705,19 @@ impl Grid { /// # Panics /// /// Panics if the row index is out of bounds. - pub fn iter_row(&self, row: usize) -> Iter { - if row < self.rows { - let start = row * self.cols; - self.data[start..(start + self.cols)].iter() - } else { - panic!( - "out of bounds. Row must be less than {:?}, but is {:?}.", - self.rows, row - ) + pub fn iter_row(&self, row: usize) -> StepBy> { + assert!( + row < self.rows, + "out of bounds. Row must be less than {:?}, but is {:?}", + self.rows, + row + ); + match self.order { + Order::RowMajor => { + let start = row * self.cols; + self.data[start..(start + self.cols)].iter().step_by(1) + } + Order::ColumnMajor => self.data[row..].iter().step_by(self.rows), } } @@ -526,27 +731,33 @@ impl Grid { /// let mut col_iter = grid.iter_row_mut(1); /// let next = col_iter.next(); /// *next.unwrap() = 10; - /// assert_eq!(grid[1][0], 10); + /// assert_eq!(grid[(1, 0)], 10); /// ``` /// /// # Panics /// /// Panics if the row index is out of bounds. - pub fn iter_row_mut(&mut self, row: usize) -> IterMut { - if row < self.rows { - let cols = self.cols; - let start = row * cols; - self.data[start..(start + cols)].iter_mut() - } else { - panic!( - "out of bounds. Row must be less than {:?}, but is {:?}.", - self.rows, row - ) + pub fn iter_row_mut(&mut self, row: usize) -> StepBy> { + assert!( + row < self.rows, + "out of bounds. Row must be less than {:?}, but is {:?}", + self.rows, + row + ); + match self.order { + Order::RowMajor => { + let start = row * self.cols; + self.data[start..(start + self.cols)].iter_mut().step_by(1) + } + Order::ColumnMajor => self.data[row..].iter_mut().step_by(self.rows), } } /// Traverse the grid with row and column indexes. /// + /// The iteration order is dependant on the internal memory layout, + /// but the indexes will be acurate either way. + /// /// # Examples /// /// ``` @@ -566,10 +777,13 @@ impl Grid { /// } /// ``` pub fn indexed_iter(&self) -> impl Iterator { - self.data - .iter() - .enumerate() - .map(move |(idx, i)| ((idx / self.cols, idx % self.cols), i)) + self.data.iter().enumerate().map(move |(idx, i)| { + let position = match self.order { + Order::RowMajor => (idx / self.cols, idx % self.cols), + Order::ColumnMajor => (idx % self.rows, idx / self.rows), + }; + (position, i) + }) } /// Add a new row to the grid. @@ -582,9 +796,9 @@ impl Grid { /// let row = vec![6,7,8]; /// grid.push_row(row); /// assert_eq!(grid.rows(), 3); - /// assert_eq!(grid[2][0], 6); - /// assert_eq!(grid[2][1], 7); - /// assert_eq!(grid[2][2], 8); + /// assert_eq!(grid[(2, 0)], 6); + /// assert_eq!(grid[(2, 1)], 7); + /// assert_eq!(grid[(2, 2)], 8); /// ``` /// /// Can also be used to init an empty grid: @@ -597,6 +811,10 @@ impl Grid { /// assert_eq!(grid.size(), (1, 3)); /// ``` /// + /// # Performance + /// + /// This method will be significantly slower if the grid uses a column-major memory layout. + /// /// # Panics /// /// Panics if: @@ -611,6 +829,12 @@ impl Grid { row.len() ); self.data.extend(row); + if self.order == Order::ColumnMajor { + for i in (1..self.cols).rev() { + let col_idx = i * self.rows; + self.data[col_idx..col_idx + self.rows + i].rotate_right(i); + } + } self.rows += 1; if self.cols == 0 { self.cols = self.data.len(); @@ -619,10 +843,6 @@ impl Grid { /// Add a new column to the grid. /// - /// *Important:* - /// Please note that `Grid` uses a Row-Major memory layout. Therefore, the `push_col()` - /// operation will be significantly slower compared to a `push_row()` operation. - /// /// # Examples /// /// ``` @@ -631,8 +851,8 @@ impl Grid { /// let col = vec![4,6]; /// grid.push_col(col); /// assert_eq!(grid.cols(), 4); - /// assert_eq!(grid[0][3], 4); - /// assert_eq!(grid[1][3], 6); + /// assert_eq!(grid[(0, 3)], 4); + /// assert_eq!(grid[(1, 3)], 6); /// ``` /// /// Can also be used to init an empty grid: @@ -645,6 +865,11 @@ impl Grid { /// assert_eq!(grid.size(), (3, 1)); /// ``` /// + /// # Performance + /// + /// This method will be significantly slower if the grid uses a row-major memory layout, + /// which is the default. + /// /// # Panics /// /// Panics if: @@ -659,9 +884,11 @@ impl Grid { col.len() ); self.data.extend(col); - for i in (1..self.rows).rev() { - let row_idx = i * self.cols; - self.data[row_idx..row_idx + self.cols + i].rotate_right(i); + if self.order == Order::RowMajor { + for i in (1..self.rows).rev() { + let row_idx = i * self.cols; + self.data[row_idx..row_idx + self.cols + i].rotate_right(i); + } } self.cols += 1; if self.rows == 0 { @@ -679,11 +906,21 @@ impl Grid { /// assert_eq![grid.pop_row(), Some(vec![1,2,3])]; /// assert_eq![grid.pop_row(), None]; /// ``` + /// + /// # Performance + /// + /// This method will be significantly slower if the grid uses a column-major memory layout. pub fn pop_row(&mut self) -> Option> { if self.rows == 0 { return None; } - let row = self.data.split_off((self.rows - 1) * self.cols); + if self.order == Order::ColumnMajor { + for i in 1..self.cols { + let col_idx = i * (self.rows - 1); + self.data[col_idx..col_idx + self.rows + i - 1].rotate_left(i); + } + } + let row = self.data.split_off(self.data.len() - self.cols); self.rows -= 1; if self.rows == 0 { self.cols = 0; @@ -702,19 +939,33 @@ impl Grid { /// assert_eq![grid.remove_row(0), Some(vec![5,6])]; /// assert_eq![grid.remove_row(0), None]; /// ``` + /// + /// # Performance + /// + /// This method will be significantly slower if the grid uses a column-major memory layout. pub fn remove_row(&mut self, row_index: usize) -> Option> { if self.cols == 0 || self.rows == 0 || row_index >= self.rows { return None; } - let residue = self - .data - .drain((row_index * self.cols)..((row_index + 1) * self.cols)); - + let row = match self.order { + Order::RowMajor => self + .data + .drain((row_index * self.cols)..((row_index + 1) * self.cols)) + .collect(), + Order::ColumnMajor => { + for i in 0..self.cols { + let col_idx = row_index + i * (self.rows - 1); + let end = cmp::min(col_idx + self.rows + i, self.data.len()); + self.data[col_idx..end].rotate_left(i + 1); + } + self.data.split_off(self.data.len() - self.cols) + } + }; self.rows -= 1; if self.rows == 0 { self.cols = 0; } - Some(residue.collect()) + Some(row) } /// Removes the last column from a grid and returns it, or None if it is empty. @@ -731,13 +982,20 @@ impl Grid { /// assert_eq![grid.pop_col(), Some(vec![1,4])]; /// assert_eq![grid.pop_col(), None]; /// ``` + /// + /// # Performance + /// + /// This method will be significantly slower if the grid uses a row-major memory layout, + /// which is the default. pub fn pop_col(&mut self) -> Option> { if self.cols == 0 { return None; } - for i in 1..self.rows { - let row_idx = i * (self.cols - 1); - self.data[row_idx..row_idx + self.cols + i - 1].rotate_left(i); + if self.order == Order::RowMajor { + for i in 1..self.rows { + let row_idx = i * (self.cols - 1); + self.data[row_idx..row_idx + self.cols + i - 1].rotate_left(i); + } } let col = self.data.split_off(self.data.len() - self.rows); self.cols -= 1; @@ -759,16 +1017,29 @@ impl Grid { /// assert_eq![grid.remove_col(0), Some(vec![2,6,10,14])]; /// assert_eq![grid.remove_col(0), None]; /// ``` + /// + /// # Performance + /// + /// This method will be significantly slower if the grid uses a row-major memory layout, + /// which is the default. pub fn remove_col(&mut self, col_index: usize) -> Option> { if self.cols == 0 || self.rows == 0 || col_index >= self.cols { return None; } - for i in 0..self.rows { - let row_idx = col_index + i * (self.cols - 1); - let end = cmp::min(row_idx + self.cols + i, self.data.len()); - self.data[row_idx..end].rotate_left(i + 1); - } - let col = self.data.split_off(self.data.len() - self.rows); + let col = match self.order { + Order::RowMajor => { + for i in 0..self.rows { + let row_idx = col_index + i * (self.cols - 1); + let end = cmp::min(row_idx + self.cols + i, self.data.len()); + self.data[row_idx..end].rotate_left(i + 1); + } + self.data.split_off(self.data.len() - self.rows) + } + Order::ColumnMajor => self + .data + .drain((col_index * self.rows)..((col_index + 1) * self.rows)) + .collect(), + }; self.cols -= 1; if self.cols == 0 { self.rows = 0; @@ -783,12 +1054,13 @@ impl Grid { /// use grid::*; /// let mut grid = grid![[1,2,3][4,5,6]]; /// grid.insert_row(1, vec![7,8,9]); - /// assert_eq!(grid[0], [1,2,3]); - /// assert_eq!(grid[1], [7,8,9]); - /// assert_eq!(grid[2], [4,5,6]); - /// assert_eq!(grid.size(), (3,3)) + /// assert_eq!(grid, grid![[1,2,3][7,8,9][4,5,6]]); /// ``` /// + /// # Performance + /// + /// This method will be significantly slower if the grid uses a column-major memory layout. + /// /// # Panics /// /// Panics if: @@ -808,8 +1080,18 @@ impl Grid { index, self.rows ); - let data_idx = index * input_len; - self.data.splice(data_idx..data_idx, row.into_iter()); + match self.order { + Order::RowMajor => { + let data_idx = index * input_len; + self.data.splice(data_idx..data_idx, row); + } + Order::ColumnMajor => { + for (col_iter, row_val) in row.into_iter().enumerate() { + let data_idx = col_iter * self.rows + index + col_iter; + self.data.insert(data_idx, row_val); + } + } + } self.cols = input_len; self.rows += 1; } @@ -824,11 +1106,14 @@ impl Grid { /// use grid::*; /// let mut grid = grid![[1,2,3][4,5,6]]; /// grid.insert_col(1, vec![9,9]); - /// assert_eq!(grid[0], [1,9,2,3]); - /// assert_eq!(grid[1], [4,9,5,6]); - /// assert_eq!(grid.size(), (2,4)) + /// assert_eq!(grid, grid![[1,9,2,3][4,9,5,6]]) /// ``` /// + /// # Performance + /// + /// This method will be significantly slower if the grid uses a row-major memory layout, + /// which is the default. + /// /// # Panics /// /// Panics if: @@ -848,9 +1133,17 @@ impl Grid { index, self.cols ); - for (row_iter, col_val) in col.into_iter().enumerate() { - let data_idx = row_iter * self.cols + index + row_iter; - self.data.insert(data_idx, col_val); + match self.order { + Order::RowMajor => { + for (row_iter, col_val) in col.into_iter().enumerate() { + let data_idx = row_iter * self.cols + index + row_iter; + self.data.insert(data_idx, col_val); + } + } + Order::ColumnMajor => { + let data_idx = index * input_len; + self.data.splice(data_idx..data_idx, col); + } } self.rows = input_len; self.cols += 1; @@ -858,8 +1151,8 @@ impl Grid { /// Returns a reference to the internal data structure of the grid. /// - /// Grid uses a row major layout. - /// All rows are placed right after each other in the vector data structure. + /// The order of the elements depends on the internal memory layout, which is + /// row-major by default. /// /// # Examples /// ``` @@ -874,104 +1167,149 @@ impl Grid { } /// Converts self into a vector without clones or allocation. + /// + /// This vector represents the internal data structure of the grid, and + /// can be in row-major or column-major order, depending on the grid. #[must_use] pub fn into_vec(self) -> Vec { self.data } /// Transpose the grid so that columns become rows in new grid. - #[must_use] - pub fn transpose(&self) -> Grid - where - T: Clone, - { - let mut data = Vec::with_capacity(self.data.len()); - for c in 0..self.cols { - for r in 0..self.rows { - data.push(self[r][c].clone()); + /// + /// This method changes the internal memory layout. + pub fn transpose(&mut self) { + self.order = self.order.counterpart(); + core::mem::swap(&mut self.rows, &mut self.cols); + } + + /// Flip (or mirrors) the columns. + /// + /// # Examples + /// + /// ``` + /// use grid::*; + /// let mut grid = grid![[1,2,3][4,5,6]]; + /// grid.flip_cols(); + /// assert_eq!(grid, grid![[3,2,1][6,5,4]]) + /// ``` + /// + /// # Performance + /// + /// This method will be significantly slower if the grid uses a column-major memory layout. + pub fn flip_cols(&mut self) { + match self.order { + Order::RowMajor => { + for row in 0..self.rows { + let idx = row * self.cols; + self.data[idx..idx + self.cols].reverse(); + } + } + Order::ColumnMajor => { + for col in 0..self.cols / 2 { + for row in 0..self.rows { + let cell1 = self.get_index(row, col); + let cell2 = self.get_index(row, self.cols - col - 1); + self.data.swap(cell1, cell2); + } + } } - } - Grid { - data, - cols: self.rows, - rows: self.cols, } } - /// Rotate the grid 90° counter-clockwise. + /// Flip (or mirrors) the rows. /// /// # Examples /// /// ``` /// use grid::*; - /// let grid = grid![[1,2,3][4,5,6]]; - /// assert_eq!(grid.rotate_left(), grid![[3,6][2,5][1,4]]); + /// let mut grid = grid![[1,2,3][4,5,6]]; + /// grid.flip_rows(); + /// assert_eq!(grid, grid![[4,5,6][1,2,3]]) /// ``` - #[must_use] - pub fn rotate_left(&self) -> Grid - where - T: Clone, - { - let mut data = Vec::with_capacity(self.data.len()); - for c in (0..self.cols).rev() { - for r in 0..self.rows { - data.push(self[r][c].clone()); + /// + /// # Performance + /// + /// This method will be significantly slower if the grid uses a row-major memory layout, + /// which is the default. + pub fn flip_rows(&mut self) { + match self.order { + Order::RowMajor => { + for row in 0..self.rows / 2 { + for col in 0..self.cols { + let cell1 = self.get_index(row, col); + let cell2 = self.get_index(self.rows - row - 1, col); + self.data.swap(cell1, cell2); + } + } + } + Order::ColumnMajor => { + for col in 0..self.cols { + let idx = col * self.rows; + self.data[idx..idx + self.rows].reverse(); + } } } - Grid { - data, - cols: self.rows, - rows: self.cols, - } + } + + /// Rotate the grid 90° counter-clockwise. + /// + /// This method changes the internal memory layout. + /// + /// # Examples + /// + /// ``` + /// use grid::*; + /// let mut grid = grid![[1,2][3,4]]; + /// grid.rotate_left(); + /// assert_eq!(grid, grid![[2,4][1,3]]); + /// ``` + /// + /// # Performance + /// + /// This method will be significantly slower if the grid initialy uses a column-major memory layout, + /// which is the default. + pub fn rotate_left(&mut self) { + self.transpose(); + self.flip_rows(); } /// Rotate the grid 90° clockwise. /// + /// This method changes the internal memory layout. + /// /// # Examples /// /// ``` /// use grid::*; - /// let grid = grid![[1,2,3][4,5,6]]; - /// assert_eq!(grid.rotate_right(), grid![[4,1][5,2][6,3]]); + /// let mut grid = grid![[1,2][3,4]]; + /// grid.rotate_right(); + /// assert_eq!(grid, grid![[3,1][4,2]]); /// ``` - #[must_use] - pub fn rotate_right(&self) -> Grid - where - T: Clone, - { - let mut data = Vec::with_capacity(self.data.len()); - for c in 0..self.cols { - for r in (0..self.rows).rev() { - data.push(self[r][c].clone()); - } - } - Grid { - data, - cols: self.rows, - rows: self.cols, - } + /// + /// # Performance + /// + /// This method will be significantly slower if the grid initialy uses a row-major memory layout, + /// which is the default. + pub fn rotate_right(&mut self) { + self.transpose(); + self.flip_cols(); } /// Rotate the grid 180°. /// + /// This method **doesn't** change the internal memory layout. + /// /// # Examples /// /// ``` /// use grid::*; - /// let grid = grid![[1,2,3][4,5,6]]; - /// assert_eq!(grid.rotate_half(), grid![[6,5,4][3,2,1]]); + /// let mut grid = grid![[1,2,3][4,5,6]]; + /// grid.rotate_half(); + /// assert_eq!(grid, grid![[6,5,4][3,2,1]]); /// ``` - #[must_use] - pub fn rotate_half(&self) -> Grid - where - T: Clone, - { - let data: Vec<_> = self.data.iter().rev().cloned().collect(); - Grid { - data, - cols: self.cols, - rows: self.rows, - } + pub fn rotate_half(&mut self) { + self.data.reverse(); } /// Fills the grid with elements by cloning `value`. @@ -982,8 +1320,7 @@ impl Grid { /// use grid::*; /// let mut grid = grid![[1,2,3][4,5,6]]; /// grid.fill(7); - /// assert_eq!(grid[0], [7,7,7]); - /// assert_eq!(grid[1], [7,7,7]); + /// assert_eq!(grid, grid![[7,7,7][7,7,7]]); /// ``` pub fn fill(&mut self, value: T) where @@ -1007,8 +1344,7 @@ impl Grid { /// use grid::*; /// let mut grid = grid![[1,2,3][4,5,6]]; /// grid.fill_with(Default::default); - /// assert_eq!(grid[0], [0,0,0]); - /// assert_eq!(grid[1], [0,0,0]); + /// assert_eq!(grid, grid![[0,0,0][0,0,0]]); /// ``` pub fn fill_with(&mut self, f: F) where @@ -1068,30 +1404,13 @@ impl Clone for Grid { rows: self.rows, cols: self.cols, data: self.data.clone(), + order: self.order, } } } -impl Index for Grid { - type Output = [T]; - - #[inline] - fn index(&self, idx: usize) -> &[T] { - let start_idx = idx * self.cols; - &self.data[start_idx..start_idx + self.cols] - } -} - -impl IndexMut for Grid { - #[inline] - fn index_mut(&mut self, idx: usize) -> &mut [T] { - let start_idx = idx * self.cols; - &mut self.data[start_idx..start_idx + self.cols] - } -} - -impl Index<(usize, usize)> for Grid { - type Output = T; +impl Index<(usize, usize)> for Grid { + type Output = T; #[inline] fn index(&self, (row, col): (usize, usize)) -> &T { @@ -1101,7 +1420,8 @@ impl Index<(usize, usize)> for Grid { self.rows, self.cols ); - &self.data[row * self.cols + col] + let index = self.get_index(row, col); + &self.data[index] } } @@ -1114,53 +1434,45 @@ impl IndexMut<(usize, usize)> for Grid { self.rows, self.cols ); - &mut self.data[row * self.cols + col] + let index = self.get_index(row, col); + &mut self.data[index] } } impl fmt::Debug for Grid { - #[allow(unused_must_use)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "["); + write!(f, "[")?; if self.cols > 0 { if f.alternate() { - writeln!(f); + writeln!(f)?; /* WARNING Compound types becoming enormous as the entire `fmt::Debug` width is applied to each item individually. For tuples and structs define padding and precision arguments manually to improve readability. */ - let width = f.width().unwrap_or( - /* - Conditionally calculate the longest item by default. - */ + let width = f.width().unwrap_or_else(|| { + // Conditionally calculate the longest item by default. self.data .iter() .map(|i| format!("{i:?}").len()) .max() - .unwrap(), - ); + .unwrap() + }); let precision = f.precision().unwrap_or(2); - for (i, _) in self.data.iter().enumerate().step_by(self.cols) { - let mut row = self.data[i..(i + self.cols)].iter().peekable(); - write!(f, " ["); + for mut row in self.iter_rows().map(Iterator::peekable) { + write!(f, " [")?; while let Some(item) = row.next() { - write!( - f, - " {item:width$.precision$?}", - // width = width, - // precision = precision - ); + write!(f, " {item:width$.precision$?}")?; if row.peek().is_some() { - write!(f, ","); + write!(f, ",")?; } } - writeln!(f, "]"); + writeln!(f, "]")?; } } else { - for (i, _) in self.data.iter().enumerate().step_by(self.cols) { - write!(f, "{:?}", &self.data[i..(i + self.cols)]); + for row in self.iter_rows() { + f.debug_list().entries(row).finish()?; } } } @@ -1170,7 +1482,18 @@ impl fmt::Debug for Grid { impl PartialEq for Grid { fn eq(&self, other: &Self) -> bool { - self.rows == other.rows && self.cols == other.cols && self.data == other.data + if self.rows != other.rows || self.cols != other.cols { + return false; + } + if self.order == other.order { + return self.data == other.data; + } + for (self_row, other_row) in core::iter::zip(self.iter_rows(), other.iter_rows()) { + if self_row.ne(other_row) { + return false; + } + } + true } } @@ -1186,7 +1509,7 @@ pub struct GridColIter<'a, T> { } impl<'a, T> Iterator for GridRowIter<'a, T> { - type Item = Iter<'a, T>; + type Item = StepBy>; fn next(&mut self) -> Option { let rows = self.grid.rows(); @@ -1225,148 +1548,342 @@ mod test { #[cfg(not(feature = "std"))] use alloc::string::String; + fn test_grid(grid: &Grid, rows: usize, cols: usize, order: Order, data: &[T]) + where + T: fmt::Debug + PartialEq, + { + assert_eq!(grid.rows, rows, "number of rows is unexpected"); + assert_eq!(grid.cols, cols, "number of cols is unexpected"); + assert_eq!(grid.order, order, "grid order is unexpected"); + assert_eq!(grid.data, data, "internal data is unexpected"); + } + #[test] fn from_vec_zero_with_cols() { let grid: Grid = Grid::from_vec(vec![], 1); - assert_eq!(grid.rows(), 0); - assert_eq!(grid.cols(), 0); + test_grid(&grid, 0, 0, Order::RowMajor, &[]); } #[test] fn from_vec_zero() { let grid: Grid = Grid::from_vec(vec![], 0); - let _ = grid.is_empty(); - assert_eq!(grid.rows(), 0); - assert_eq!(grid.cols(), 0); + test_grid(&grid, 0, 0, Order::RowMajor, &[]); + } + + #[test] + #[should_panic] + fn from_vec_panics_1() { + let _: Grid = Grid::from_vec(vec![1, 2, 3], 0); + } + + #[test] + #[should_panic] + fn from_vec_panics_2() { + let _: Grid = Grid::from_vec(vec![1, 2, 3], 2); + } + + #[test] + fn from_vec_uses_original_vec() { + let capacity = 10_000_000; + let vec = Vec::with_capacity(capacity); + let grid: Grid = Grid::from_vec(vec, 0); + assert!(grid.into_vec().capacity() >= capacity); + } + + #[test] + fn from_vec_with_order_zero_with_cols() { + let grid: Grid = Grid::from_vec_with_order(vec![], 1, Order::ColumnMajor); + test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); + } + + #[test] + fn from_vec_with_order_zero() { + let grid: Grid = Grid::from_vec_with_order(vec![], 0, Order::ColumnMajor); + test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); + } + + #[test] + #[should_panic] + fn from_vec_with_order_panics_1() { + let _: Grid = Grid::from_vec_with_order(vec![1, 2, 3], 0, Order::ColumnMajor); + } + + #[test] + #[should_panic] + fn from_vec_with_order_panics_2() { + let _: Grid = Grid::from_vec_with_order(vec![1, 2, 3], 2, Order::ColumnMajor); + } + + #[test] + fn from_vec_with_order_uses_original_vec() { + let capacity = 10_000_000; + let vec = Vec::with_capacity(capacity); + let grid: Grid = Grid::from_vec_with_order(vec, 0, Order::ColumnMajor); + assert!(grid.into_vec().capacity() >= capacity); } #[test] fn insert_col_at_end() { - let mut grid: Grid = Grid::from_vec(vec![1, 2, 3, 4], 2); + let mut grid: Grid = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::RowMajor); grid.insert_col(2, vec![5, 6]); - assert_eq!(grid[0], [1, 2, 5]); - assert_eq!(grid[1], [3, 4, 6]); + test_grid(&grid, 2, 3, Order::RowMajor, &[1, 2, 5, 3, 4, 6]); } #[test] #[should_panic] fn insert_col_out_of_idx() { - let mut grid: Grid = Grid::from_vec(vec![1, 2, 3, 4], 2); + let mut grid: Grid = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::RowMajor); grid.insert_col(3, vec![4, 5]); } #[test] - fn insert_row_at_end() { - let mut grid: Grid = Grid::from_vec(vec![1, 2, 3, 4], 2); - grid.insert_row(2, vec![5, 6]); - assert_eq!(grid[0], [1, 2]); - assert_eq!(grid[1], [3, 4]); - assert_eq!(grid[2], [5, 6]); + fn insert_col_empty() { + let mut grid: Grid = Grid::from_vec_with_order(vec![], 0, Order::RowMajor); + grid.insert_col(0, vec![1, 2, 3]); + test_grid(&grid, 3, 1, Order::RowMajor, &[1, 2, 3]); } #[test] - fn insert_row_empty() { - let mut grid: Grid = grid![]; - grid.insert_row(0, vec![1, 2, 3]); - assert_eq!(grid[0], [1, 2, 3]); - assert_eq!((1, 3), grid.size()); + fn insert_col_at_end_column_major() { + let mut grid: Grid = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor); + grid.insert_col(2, vec![5, 6]); + test_grid(&grid, 2, 3, Order::ColumnMajor, &[1, 3, 2, 4, 5, 6]); } #[test] - fn insert_col_empty() { - let mut grid: Grid = grid![]; + #[should_panic] + fn insert_col_out_of_idx_column_major() { + let mut grid: Grid = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor); + grid.insert_col(3, vec![4, 5]); + } + + #[test] + fn insert_col_empty_column_major() { + let mut grid: Grid = Grid::from_vec_with_order(vec![], 0, Order::ColumnMajor); grid.insert_col(0, vec![1, 2, 3]); - assert_eq!(grid[0], [1]); - assert_eq!((3, 1), grid.size()); + test_grid(&grid, 3, 1, Order::ColumnMajor, &[1, 2, 3]); + } + + #[test] + fn insert_row_at_end() { + let mut grid: Grid = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::RowMajor); + grid.insert_row(2, vec![5, 6]); + test_grid(&grid, 3, 2, Order::RowMajor, &[1, 2, 3, 4, 5, 6]); + } + + #[test] + fn insert_row_empty() { + let mut grid: Grid = Grid::from_vec_with_order(vec![], 0, Order::RowMajor); + grid.insert_row(0, vec![1, 2, 3]); + test_grid(&grid, 1, 3, Order::RowMajor, &[1, 2, 3]); } #[test] #[should_panic] fn insert_row_out_of_idx() { - let mut grid: Grid = Grid::from_vec(vec![1, 2, 3, 4], 2); + let mut grid: Grid = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::RowMajor); grid.insert_row(3, vec![4, 5]); } #[test] #[should_panic] fn insert_row_wrong_size_of_idx() { - let mut grid: Grid = Grid::from_vec(vec![1, 2, 3, 4], 2); + let mut grid: Grid = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::RowMajor); grid.insert_row(1, vec![4, 5, 4]); } #[test] fn insert_row_start() { - let mut grid: Grid = Grid::from_vec(vec![1, 2, 3, 4], 2); - let new_row = [5, 6]; - grid.insert_row(1, new_row.to_vec()); - assert_eq!(grid[1], new_row); + let mut grid: Grid = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::RowMajor); + grid.insert_row(1, vec![5, 6]); + test_grid(&grid, 3, 2, Order::RowMajor, &[1, 2, 5, 6, 3, 4]); + } + + #[test] + fn insert_row_at_end_column_major() { + let mut grid: Grid = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor); + grid.insert_row(2, vec![5, 6]); + test_grid(&grid, 3, 2, Order::ColumnMajor, &[1, 3, 5, 2, 4, 6]); + } + + #[test] + fn insert_row_empty_column_major() { + let mut grid: Grid = Grid::from_vec_with_order(vec![], 0, Order::ColumnMajor); + grid.insert_row(0, vec![1, 2, 3]); + test_grid(&grid, 1, 3, Order::ColumnMajor, &[1, 2, 3]); + } + + #[test] + #[should_panic] + fn insert_row_out_of_idx_column_major() { + let mut grid: Grid = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::ColumnMajor); + grid.insert_row(3, vec![4, 5]); + } + + #[test] + #[should_panic] + fn insert_row_wrong_size_of_idx_column_major() { + let mut grid: Grid = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::ColumnMajor); + grid.insert_row(1, vec![4, 5, 4]); + } + + #[test] + fn insert_row_start_column_major() { + let mut grid: Grid = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor); + grid.insert_row(1, vec![5, 6]); + test_grid(&grid, 3, 2, Order::ColumnMajor, &[1, 5, 3, 2, 6, 4]); } #[test] fn pop_col_1x3() { - let mut grid: Grid = Grid::from_vec(vec![1, 2, 3], 3); + let mut grid: Grid = Grid::from_vec_with_order(vec![1, 2, 3], 3, Order::RowMajor); assert_eq!(grid.pop_col(), Some(vec![3])); - assert_eq!(grid.size(), (1, 2)); + test_grid(&grid, 1, 2, Order::RowMajor, &[1, 2]); assert_eq!(grid.pop_col(), Some(vec![2])); - assert_eq!(grid.size(), (1, 1)); + test_grid(&grid, 1, 1, Order::RowMajor, &[1]); assert_eq!(grid.pop_col(), Some(vec![1])); - assert!(grid.is_empty()); + test_grid(&grid, 0, 0, Order::RowMajor, &[]); assert_eq!(grid.pop_col(), None); + test_grid(&grid, 0, 0, Order::RowMajor, &[]); } #[test] fn pop_col_3x1() { - let mut grid: Grid = Grid::from_vec(vec![1, 2, 3], 1); + let mut grid: Grid = Grid::from_vec_with_order(vec![1, 2, 3], 1, Order::RowMajor); assert_eq!(grid.pop_col(), Some(vec![1, 2, 3])); - assert!(grid.is_empty()); + test_grid(&grid, 0, 0, Order::RowMajor, &[]); assert_eq!(grid.pop_col(), None); + test_grid(&grid, 0, 0, Order::RowMajor, &[]); } #[test] fn pop_col_2x2() { - let mut grid: Grid = Grid::from_vec(vec![1, 2, 3, 4], 2); + let mut grid: Grid = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::RowMajor); assert_eq!(grid.pop_col(), Some(vec![2, 4])); assert_eq!(grid.size(), (2, 1)); + test_grid(&grid, 2, 1, Order::RowMajor, &[1, 3]); assert_eq!(grid.pop_col(), Some(vec![1, 3])); - assert_eq!(grid.size(), (0, 0)); + test_grid(&grid, 0, 0, Order::RowMajor, &[]); assert_eq!(grid.pop_col(), None); + test_grid(&grid, 0, 0, Order::RowMajor, &[]); } #[test] fn pop_col_3x4() { - let mut grid: Grid = - Grid::from_vec(vec![1, 2, 3, 4, 11, 22, 33, 44, 111, 222, 333, 444], 4); + let internal = vec![1, 2, 3, 4, 11, 22, 33, 44, 111, 222, 333, 444]; + let mut grid: Grid = Grid::from_vec_with_order(internal, 4, Order::RowMajor); assert_eq!(grid.pop_col(), Some(vec![4, 44, 444])); - assert_eq!(grid.size(), (3, 3)); + let expected = [1, 2, 3, 11, 22, 33, 111, 222, 333]; + test_grid(&grid, 3, 3, Order::RowMajor, &expected); assert_eq!(grid.pop_col(), Some(vec![3, 33, 333])); - assert_eq!(grid.size(), (3, 2)); + test_grid(&grid, 3, 2, Order::RowMajor, &[1, 2, 11, 22, 111, 222]); assert_eq!(grid.pop_col(), Some(vec![2, 22, 222])); - assert_eq!(grid.size(), (3, 1)); + test_grid(&grid, 3, 1, Order::RowMajor, &[1, 11, 111]); assert_eq!(grid.pop_col(), Some(vec![1, 11, 111])); - assert_eq!(grid.size(), (0, 0)); + test_grid(&grid, 0, 0, Order::RowMajor, &[]); assert_eq!(grid.pop_col(), None); + test_grid(&grid, 0, 0, Order::RowMajor, &[]); } #[test] fn pop_col_empty() { - let mut grid: Grid = Grid::from_vec(vec![], 0); - assert_eq!(grid.pop_row(), None); + let mut grid: Grid = Grid::from_vec_with_order(vec![], 0, Order::RowMajor); + assert_eq!(grid.pop_col(), None); + test_grid(&grid, 0, 0, Order::RowMajor, &[]); + } + + #[test] + fn pop_col_1x3_column_major() { + let mut grid: Grid = Grid::from_vec_with_order(vec![1, 2, 3], 3, Order::ColumnMajor); + assert_eq!(grid.pop_col(), Some(vec![3])); + test_grid(&grid, 1, 2, Order::ColumnMajor, &[1, 2]); + assert_eq!(grid.pop_col(), Some(vec![2])); + test_grid(&grid, 1, 1, Order::ColumnMajor, &[1]); + assert_eq!(grid.pop_col(), Some(vec![1])); + test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); + assert_eq!(grid.pop_col(), None); + test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); + } + + #[test] + fn pop_col_3x1_column_major() { + let mut grid: Grid = Grid::from_vec_with_order(vec![1, 2, 3], 1, Order::ColumnMajor); + assert_eq!(grid.pop_col(), Some(vec![1, 2, 3])); + test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); + assert_eq!(grid.pop_col(), None); + test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); + } + + #[test] + fn pop_col_2x2_column_major() { + let mut grid: Grid = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor); + assert_eq!(grid.pop_col(), Some(vec![2, 4])); + assert_eq!(grid.size(), (2, 1)); + test_grid(&grid, 2, 1, Order::ColumnMajor, &[1, 3]); + assert_eq!(grid.pop_col(), Some(vec![1, 3])); + test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); + assert_eq!(grid.pop_col(), None); + test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); + } + + #[test] + fn pop_col_3x4_column_major() { + let internal = vec![1, 11, 111, 2, 22, 222, 3, 33, 333, 4, 44, 444]; + let mut grid: Grid = Grid::from_vec_with_order(internal, 4, Order::ColumnMajor); + assert_eq!(grid.pop_col(), Some(vec![4, 44, 444])); + let expected = [1, 11, 111, 2, 22, 222, 3, 33, 333]; + test_grid(&grid, 3, 3, Order::ColumnMajor, &expected); + assert_eq!(grid.pop_col(), Some(vec![3, 33, 333])); + test_grid(&grid, 3, 2, Order::ColumnMajor, &[1, 11, 111, 2, 22, 222]); + assert_eq!(grid.pop_col(), Some(vec![2, 22, 222])); + test_grid(&grid, 3, 1, Order::ColumnMajor, &[1, 11, 111]); + assert_eq!(grid.pop_col(), Some(vec![1, 11, 111])); + test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); + assert_eq!(grid.pop_col(), None); + test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); + } + + #[test] + fn pop_col_empty_column_major() { + let mut grid: Grid = Grid::from_vec_with_order(vec![], 0, Order::ColumnMajor); + assert_eq!(grid.pop_col(), None); + test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); } #[test] fn pop_row_2x2() { let mut grid: Grid = Grid::from_vec(vec![1, 2, 3, 4], 2); assert_eq!(grid.pop_row(), Some(vec![3, 4])); - assert_ne!(grid.size(), (1, 4)); + test_grid(&grid, 1, 2, Order::RowMajor, &[1, 2]); assert_eq!(grid.pop_row(), Some(vec![1, 2])); - assert_eq!(grid.size(), (0, 0)); + test_grid(&grid, 0, 0, Order::RowMajor, &[]); assert_eq!(grid.pop_row(), None); + test_grid(&grid, 0, 0, Order::RowMajor, &[]); } #[test] fn pop_row_empty() { let mut grid: Grid = Grid::from_vec(vec![], 0); assert_eq!(grid.pop_row(), None); + test_grid(&grid, 0, 0, Order::RowMajor, &[]); + } + + #[test] + fn pop_row_2x2_column_major() { + let mut grid: Grid = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor); + assert_eq!(grid.pop_row(), Some(vec![3, 4])); + test_grid(&grid, 1, 2, Order::ColumnMajor, &[1, 2]); + assert_eq!(grid.pop_row(), Some(vec![1, 2])); + test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); + assert_eq!(grid.pop_row(), None); + test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); + } + + #[test] + fn pop_row_empty_column_major() { + let mut grid: Grid = Grid::from_vec_with_order(vec![], 0, Order::ColumnMajor); + assert_eq!(grid.pop_row(), None); + test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); } #[test] @@ -1396,6 +1913,7 @@ mod test { let grid2: Grid = grid![]; assert_eq!(grid, grid2); } + #[test] fn equal() { let grid: Grid = grid![['a', 'b', 'c', 'd']['a', 'b', 'c', 'd']['a', 'b', 'c', 'd']]; @@ -1404,10 +1922,10 @@ mod test { } #[test] - #[should_panic] - fn idx_out_of_col_bounds() { - let grid: Grid = grid![['a', 'b', 'c', 'd']['a', 'b', 'c', 'd']['a', 'b', 'c', 'd']]; - let _ = grid[0][5]; + fn equal_different_order() { + let grid = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::RowMajor); + let grid2 = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor); + assert_eq!(grid, grid2); } #[test] @@ -1419,57 +1937,38 @@ mod test { #[test] fn push_col_2x3() { - let mut grid: Grid = grid![ + let mut grid: Grid = grid![ [0, 1, 2] [10, 11, 12]]; grid.push_col(vec![3, 13]); - assert_eq!(grid.size(), (2, 4)); - assert_eq!( - grid.iter_row(0).copied().collect::>(), - vec![0, 1, 2, 3] - ); - assert_eq!( - grid.iter_row(1).copied().collect::>(), - vec![10, 11, 12, 13] - ); + test_grid(&grid, 2, 4, Order::RowMajor, &[0, 1, 2, 3, 10, 11, 12, 13]); } #[test] fn push_col_3x4() { - let mut grid: Grid = grid![ + let mut grid: Grid = grid![ ['a', 'b', 'c', 'd'] ['a', 'b', 'c', 'd'] ['a', 'b', 'c', 'd']]; grid.push_col(vec!['x', 'y', 'z']); - assert_eq!(grid.size(), (3, 5)); - assert_eq!( - grid.iter_row(0).copied().collect::>(), - vec!['a', 'b', 'c', 'd', 'x'] - ); - assert_eq!( - grid.iter_row(1).copied().collect::>(), - vec!['a', 'b', 'c', 'd', 'y'] - ); - assert_eq!( - grid.iter_row(2).copied().collect::>(), - vec!['a', 'b', 'c', 'd', 'z'] - ); + let expected = [ + 'a', 'b', 'c', 'd', 'x', 'a', 'b', 'c', 'd', 'y', 'a', 'b', 'c', 'd', 'z', + ]; + test_grid(&grid, 3, 5, Order::RowMajor, &expected); } #[test] fn push_col_1x3() { let mut grid: Grid = grid![['a', 'b', 'c']]; grid.push_col(vec!['d']); - assert_eq!(grid.size(), (1, 4)); - assert_eq!(grid[0][3], 'd'); + test_grid(&grid, 1, 4, Order::RowMajor, &['a', 'b', 'c', 'd']); } #[test] fn push_col_empty() { let mut grid: Grid = grid![]; grid.push_col(vec!['b', 'b', 'b', 'b']); - assert_eq!(grid.size(), (4, 1)); - assert_eq!(grid[0][0], 'b'); + test_grid(&grid, 4, 1, Order::RowMajor, &['b', 'b', 'b', 'b']); } #[test] @@ -1487,12 +1986,68 @@ mod test { grid.push_col(vec![]); } + #[test] + fn push_col_2x3_column_major() { + let internal = vec![0, 10, 1, 11, 2, 12]; + let mut grid: Grid = Grid::from_vec_with_order(internal, 3, Order::ColumnMajor); + grid.push_col(vec![3, 13]); + let expected = [0, 10, 1, 11, 2, 12, 3, 13]; + test_grid(&grid, 2, 4, Order::ColumnMajor, &expected); + } + + #[test] + fn push_col_3x4_column_major() { + let internal = vec!['a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'd']; + let mut grid: Grid = Grid::from_vec_with_order(internal, 4, Order::ColumnMajor); + grid.push_col(vec!['x', 'y', 'z']); + let expected = [ + 'a', 'a', 'a', 'b', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'd', 'x', 'y', 'z', + ]; + test_grid(&grid, 3, 5, Order::ColumnMajor, &expected); + } + + #[test] + fn push_col_1x3_column_major() { + let mut grid: Grid = + Grid::from_vec_with_order(vec!['a', 'b', 'c'], 3, Order::ColumnMajor); + grid.push_col(vec!['d']); + test_grid(&grid, 1, 4, Order::ColumnMajor, &['a', 'b', 'c', 'd']); + } + + #[test] + fn push_col_empty_column_major() { + let mut grid: Grid = Grid::new_with_order(0, 0, Order::ColumnMajor); + grid.push_col(vec!['b', 'b', 'b', 'b']); + test_grid(&grid, 4, 1, Order::ColumnMajor, &['b', 'b', 'b', 'b']); + } + + #[test] + #[should_panic] + fn push_col_wrong_size_column_major() { + let mut grid: Grid = Grid::init_with_order(2, 3, Order::ColumnMajor, 'a'); + grid.push_col(vec!['b']); + grid.push_col(vec!['b', 'b']); + } + + #[test] + #[should_panic] + fn push_col_zero_len_column_major() { + let mut grid: Grid = Grid::new_with_order(0, 0, Order::ColumnMajor); + grid.push_col(vec![]); + } + + #[test] + fn push_row() { + let mut grid: Grid = grid![[1, 2][3, 4]]; + grid.push_row(vec![5, 6]); + test_grid(&grid, 3, 2, Order::RowMajor, &[1, 2, 3, 4, 5, 6]) + } + #[test] fn push_row_empty() { let mut grid: Grid = grid![]; grid.push_row(vec!['b', 'b', 'b', 'b']); - assert_eq!(grid.size(), (1, 4)); - assert_eq!(grid[0][0], 'b'); + test_grid(&grid, 1, 4, Order::RowMajor, &['b', 'b', 'b', 'b']) } #[test] @@ -1510,44 +2065,204 @@ mod test { grid.push_row(vec!['b', 'b', 'b', 'b']); } + #[test] + fn push_row_column_major() { + let mut grid: Grid = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor); + grid.push_row(vec![5, 6]); + test_grid(&grid, 3, 2, Order::ColumnMajor, &[1, 3, 5, 2, 4, 6]) + } + + #[test] + fn push_row_empty_column_major() { + let mut grid: Grid = Grid::new_with_order(0, 0, Order::ColumnMajor); + grid.push_row(vec!['b', 'b', 'b', 'b']); + test_grid(&grid, 1, 4, Order::ColumnMajor, &['b', 'b', 'b', 'b']) + } + + #[test] + #[should_panic] + fn push_empty_row_column_major() { + let mut grid = Grid::init_with_order(0, 1, Order::ColumnMajor, 0); + grid.push_row(vec![]); + } + + #[test] + #[should_panic] + fn push_row_wrong_size_column_major() { + let mut grid: Grid = + Grid::from_vec_with_order(vec!['a', 'a', 'a', 'a', 'a', 'a'], 3, Order::ColumnMajor); + grid.push_row(vec!['b']); + grid.push_row(vec!['b', 'b', 'b', 'b']); + } + #[test] fn iter_row() { - let grid: Grid = grid![[1,2,3][1,2,3]]; - let mut iter = grid.iter_row(0); - assert_eq!(iter.next(), Some(&1)); - assert_eq!(iter.next(), Some(&2)); - assert_eq!(iter.next(), Some(&3)); - assert_eq!(iter.next(), None); + let grid = Grid::from_vec_with_order(vec![1, 2, 3, 4, 5, 6], 3, Order::RowMajor); + let row: Vec<_> = grid.iter_row(1).collect(); + assert_eq!(row, [&4, &5, &6]); } #[test] #[should_panic] - fn iter_row_empty() { - let grid: Grid = grid![]; + fn iter_row_out_of_bound() { + let grid = Grid::from_vec_with_order(vec![1, 2, 3, 4, 5, 6], 3, Order::RowMajor); + let _ = grid.iter_row(3); + } + + #[test] + #[should_panic] + fn iter_row_zero() { + let grid: Grid = Grid::from_vec_with_order(vec![], 0, Order::RowMajor); let _ = grid.iter_row(0); } + #[test] + fn iter_row_rowumn_major() { + let grid = Grid::from_vec_with_order(vec![1, 4, 2, 5, 3, 6], 3, Order::ColumnMajor); + let row: Vec<_> = grid.iter_row(1).collect(); + assert_eq!(row, [&4, &5, &6]); + } + #[test] #[should_panic] - fn iter_row_out_of_bound() { - let grid: Grid = grid![[1,2,3][1,2,3]]; - let _ = grid.iter_row(2); + fn iter_row_rowumn_major_out_of_bound() { + let grid = Grid::from_vec_with_order(vec![1, 4, 2, 5, 3, 6], 3, Order::ColumnMajor); + let _ = grid.iter_row(3); + } + + #[test] + #[should_panic] + fn iter_row_rowumn_major_zero() { + let grid: Grid = Grid::from_vec_with_order(vec![], 0, Order::ColumnMajor); + let _ = grid.iter_row(0); + } + + #[test] + fn iter_row_mut() { + let mut grid = Grid::from_vec_with_order(vec![1, 2, 3, 4, 5, 6], 3, Order::RowMajor); + let row: Vec<_> = grid.iter_row_mut(1).collect(); + assert_eq!(row, [&mut 4, &mut 5, &mut 6]); + } + + #[test] + #[should_panic] + fn iter_row_mut_out_of_bound() { + let mut grid = Grid::from_vec_with_order(vec![1, 2, 3, 4, 5, 6], 3, Order::RowMajor); + let _ = grid.iter_row_mut(3); + } + + #[test] + #[should_panic] + fn iter_row_mut_zero() { + let mut grid: Grid = Grid::from_vec_with_order(vec![], 0, Order::RowMajor); + let _ = grid.iter_row_mut(0); + } + + #[test] + fn iter_row_mut_rowumn_major() { + let mut grid = Grid::from_vec_with_order(vec![1, 4, 2, 5, 3, 6], 3, Order::ColumnMajor); + let row: Vec<_> = grid.iter_row_mut(1).collect(); + assert_eq!(row, [&mut 4, &mut 5, &mut 6]); + } + + #[test] + #[should_panic] + fn iter_row_mut_rowumn_major_out_of_bound() { + let mut grid = Grid::from_vec_with_order(vec![1, 4, 2, 5, 3, 6], 3, Order::ColumnMajor); + let _ = grid.iter_row_mut(3); + } + + #[test] + #[should_panic] + fn iter_row_mut_rowumn_major_zero() { + let mut grid: Grid = Grid::from_vec_with_order(vec![], 0, Order::ColumnMajor); + let _ = grid.iter_row_mut(0); + } + + #[test] + fn iter_col() { + let grid = Grid::from_vec_with_order(vec![1, 2, 3, 4, 5, 6], 3, Order::RowMajor); + let col: Vec<_> = grid.iter_col(1).collect(); + assert_eq!(col, [&2, &5]); } #[test] #[should_panic] fn iter_col_out_of_bound() { - let grid: Grid = grid![[1,2,3][1,2,3]]; + let grid = Grid::from_vec_with_order(vec![1, 2, 3, 4, 5, 6], 3, Order::RowMajor); let _ = grid.iter_col(3); } #[test] #[should_panic] fn iter_col_zero() { - let grid: Grid = grid![]; + let grid: Grid = Grid::from_vec_with_order(vec![], 0, Order::RowMajor); + let _ = grid.iter_col(0); + } + + #[test] + fn iter_col_column_major() { + let grid = Grid::from_vec_with_order(vec![1, 4, 2, 5, 3, 6], 3, Order::ColumnMajor); + let col: Vec<_> = grid.iter_col(1).collect(); + assert_eq!(col, [&2, &5]); + } + + #[test] + #[should_panic] + fn iter_col_column_major_out_of_bound() { + let grid = Grid::from_vec_with_order(vec![1, 4, 2, 5, 3, 6], 3, Order::ColumnMajor); + let _ = grid.iter_col(3); + } + + #[test] + #[should_panic] + fn iter_col_column_major_zero() { + let grid: Grid = Grid::from_vec_with_order(vec![], 0, Order::ColumnMajor); let _ = grid.iter_col(0); } + #[test] + fn iter_col_mut() { + let mut grid = Grid::from_vec_with_order(vec![1, 2, 3, 4, 5, 6], 3, Order::RowMajor); + let col: Vec<_> = grid.iter_col_mut(1).collect(); + assert_eq!(col, [&mut 2, &mut 5]); + } + + #[test] + #[should_panic] + fn iter_col_mut_out_of_bound() { + let mut grid = Grid::from_vec_with_order(vec![1, 2, 3, 4, 5, 6], 3, Order::RowMajor); + let _ = grid.iter_col_mut(3); + } + + #[test] + #[should_panic] + fn iter_col_mut_zero() { + let mut grid: Grid = Grid::from_vec_with_order(vec![], 0, Order::RowMajor); + let _ = grid.iter_col_mut(0); + } + + #[test] + fn iter_col_mut_column_major() { + let mut grid = Grid::from_vec_with_order(vec![1, 4, 2, 5, 3, 6], 3, Order::ColumnMajor); + let col: Vec<_> = grid.iter_col_mut(1).collect(); + assert_eq!(col, [&mut 2, &mut 5]); + } + + #[test] + #[should_panic] + fn iter_col_mut_column_major_out_of_bound() { + let mut grid = Grid::from_vec_with_order(vec![1, 4, 2, 5, 3, 6], 3, Order::ColumnMajor); + let _ = grid.iter_col_mut(3); + } + + #[test] + #[should_panic] + fn iter_col_mut_column_major_zero() { + let mut grid: Grid = Grid::from_vec_with_order(vec![], 0, Order::ColumnMajor); + let _ = grid.iter_col_mut(0); + } + #[test] fn iter() { let grid: Grid = grid![[1,2][3,4]]; @@ -1577,6 +2292,24 @@ mod test { assert_eq!(iter.next(), None); } + #[test] + fn indexed_iter_column_major() { + let grid: Grid = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor); + let mut iter = grid.indexed_iter(); + assert_eq!(iter.next(), Some(((0, 0), &1))); + assert_eq!(iter.next(), Some(((1, 0), &3))); + assert_eq!(iter.next(), Some(((0, 1), &2))); + assert_eq!(iter.next(), Some(((1, 1), &4))); + assert_eq!(iter.next(), None); + } + + #[test] + fn indexed_iter_empty_column_major() { + let grid: Grid = Grid::new_with_order(0, 0, Order::ColumnMajor); + let mut iter = grid.indexed_iter(); + assert_eq!(iter.next(), None); + } + #[test] fn clear() { let mut grid: Grid = grid![[1, 2, 3]]; @@ -1627,6 +2360,12 @@ mod test { assert_eq!(format!("{:?}", grid), "[[1, 2, 3][4, 5, 6][7, 8, 9]]"); } + #[test] + fn fmt_column_major() { + let grid = Grid::from_vec_with_order(vec![1, 4, 2, 5, 3, 6], 3, Order::ColumnMajor); + assert_eq!(format!("{:?}", grid), "[[1, 2, 3][4, 5, 6]]"); + } + #[test] fn fmt_pretty_empty() { let grid: Grid = grid![]; @@ -1735,24 +2474,29 @@ mod test { assert_eq!(format!("{:#5.5?}", grid), expected_output); } + #[test] + fn fmt_pretty_column_major() { + let grid = Grid::from_vec_with_order(vec![1, 4, 2, 5, 3, 6], 3, Order::ColumnMajor); + let expected_output = r#"[ + [ 1, 2, 3] + [ 4, 5, 6] +]"#; + assert_eq!(format!("{:#?}", grid), expected_output); + } + #[test] fn clone() { let grid = grid![[1, 2, 3][4, 5, 6]]; let mut clone = grid.clone(); - clone[0][2] = 10; - assert_eq!(grid[0][2], 3); - assert_eq!(clone[0][2], 10); + clone[(0, 2)] = 10; + test_grid(&grid, 2, 3, Order::RowMajor, &[1, 2, 3, 4, 5, 6]); + test_grid(&clone, 2, 3, Order::RowMajor, &[1, 2, 10, 4, 5, 6]); } #[test] fn macro_init() { let grid = grid![[1, 2, 3][4, 5, 6]]; - assert_eq!(grid[0][0], 1); - assert_eq!(grid[0][1], 2); - assert_eq!(grid[0][2], 3); - assert_eq!(grid[1][0], 4); - assert_eq!(grid[1][1], 5); - assert_eq!(grid[1][2], 6); + test_grid(&grid, 2, 3, Order::RowMajor, &[1, 2, 3, 4, 5, 6]); } #[test] @@ -1760,7 +2504,7 @@ mod test { let grid = grid![[1, 2, 3] [4, 5, 6] [7, 8, 9]]; - assert_eq!(grid.size(), (3, 3)) + test_grid(&grid, 3, 3, Order::RowMajor, &[1, 2, 3, 4, 5, 6, 7, 8, 9]) } #[test] @@ -1768,58 +2512,101 @@ mod test { let grid = grid![['a', 'b', 'c'] ['a', 'b', 'c'] ['a', 'b', 'c']]; - assert_eq!(grid.size(), (3, 3)); - assert_eq!(grid[1][1], 'b'); + let expected = ['a', 'b', 'c', 'a', 'b', 'c', 'a', 'b', 'c']; + test_grid(&grid, 3, 3, Order::RowMajor, &expected); } #[test] fn macro_one_row() { let grid: Grid = grid![[1, 2, 3, 4]]; - assert_eq!(grid.size(), (1, 4)); - assert_eq!(grid[0][0], 1); - assert_eq!(grid[0][1], 2); - assert_eq!(grid[0][2], 3); + test_grid(&grid, 1, 4, Order::RowMajor, &[1, 2, 3, 4]); } #[test] - #[should_panic] - fn from_vec_panics_1() { - let _: Grid = Grid::from_vec(vec![1, 2, 3], 0); + fn macro2_empty() { + let grid: Grid = grid2![]; + test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); } #[test] - #[should_panic] - fn from_vec_panics_2() { - let _: Grid = Grid::from_vec(vec![1, 2, 3], 2); + fn macro2_init() { + let grid = grid2![[1, 2, 3] + [4, 5, 6] + [7, 8, 9]]; + let expected = [1, 4, 7, 2, 5, 8, 3, 6, 9]; + test_grid(&grid, 3, 3, Order::ColumnMajor, &expected); } #[test] - fn from_vec_uses_original_vec() { - let capacity = 10_000_000; - let vec = Vec::with_capacity(capacity); - let grid: Grid = Grid::from_vec(vec, 0); - assert!(grid.into_vec().capacity() >= capacity); + fn macro2_init_char() { + let grid = grid2![['a', 'b']['c', 'd']]; + test_grid(&grid, 2, 2, Order::ColumnMajor, &['a', 'c', 'b', 'd']); + } + + #[test] + fn macro2_one_row() { + let grid = grid2![[1, 2, 3, 4]]; + test_grid(&grid, 1, 4, Order::ColumnMajor, &[1, 2, 3, 4]); } #[test] fn init() { - Grid::init(1, 2, 3); - Grid::init(1, 2, 1.2); - Grid::init(1, 2, 'a'); + let grid = Grid::init(1, 2, 3); + test_grid(&grid, 1, 2, Order::RowMajor, &[3, 3]); + + let grid = Grid::init(1, 2, 1.2); + test_grid(&grid, 1, 2, Order::RowMajor, &[1.2, 1.2]); + + let grid = Grid::init(1, 2, 'a'); + test_grid(&grid, 1, 2, Order::RowMajor, &['a', 'a']); + } + + #[test] + #[should_panic] + fn init_panics() { + Grid::init(usize::MAX, 2, 3); } #[test] fn init_empty() { let grid = Grid::init(0, 1, 0); - assert!(grid.is_empty()); - assert_eq!(grid.cols(), 0); - assert_eq!(grid.rows(), 0); + test_grid(&grid, 0, 0, Order::RowMajor, &[]); + + let grid = Grid::init(1, 0, -1); + test_grid(&grid, 0, 0, Order::RowMajor, &[]); + } + + #[test] + fn init_with_order() { + let grid = Grid::init_with_order(1, 2, Order::RowMajor, 3); + test_grid(&grid, 1, 2, Order::RowMajor, &[3, 3]); + + let grid = Grid::init_with_order(1, 2, Order::ColumnMajor, 1.2); + test_grid(&grid, 1, 2, Order::ColumnMajor, &[1.2, 1.2]); + + let grid = Grid::init_with_order(1, 2, Order::ColumnMajor, 'a'); + test_grid(&grid, 1, 2, Order::ColumnMajor, &['a', 'a']); + } + + #[test] + #[should_panic] + fn init_with_order_panics() { + Grid::init_with_order(usize::MAX, 2, Order::ColumnMajor, 3); + } + + #[test] + fn init_with_order_empty() { + let grid = Grid::init_with_order(0, 1, Order::ColumnMajor, 0); + test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); + + let grid = Grid::init_with_order(1, 0, Order::RowMajor, -1); + test_grid(&grid, 0, 0, Order::RowMajor, &[]); } #[test] fn new() { let grid: Grid = Grid::new(1, 2); - assert_eq!(grid[0][0], 0); + test_grid(&grid, 1, 2, Order::RowMajor, &[0, 0]); } #[test] @@ -1831,50 +2618,79 @@ mod test { #[test] fn new_empty() { let grid: Grid = Grid::new(0, 1); - assert!(grid.is_empty()); - assert_eq!(grid.cols(), 0); - assert_eq!(grid.rows(), 0); + test_grid(&grid, 0, 0, Order::RowMajor, &[]); + + let grid: Grid = Grid::new(1, 0); + test_grid(&grid, 0, 0, Order::RowMajor, &[]); + } + + #[test] + fn new_with_order() { + let grid: Grid = Grid::new_with_order(2, 2, Order::ColumnMajor); + test_grid(&grid, 2, 2, Order::ColumnMajor, &[0, 0, 0, 0]); } #[test] #[should_panic] - fn init_panics() { - Grid::init(usize::MAX, 2, 3); + fn new_with_order_panics() { + let _: Grid = Grid::new_with_order(usize::MAX, 2, Order::ColumnMajor); + } + + #[test] + fn new_with_order_empty() { + let grid: Grid = Grid::new_with_order(0, 3, Order::RowMajor); + test_grid(&grid, 0, 0, Order::RowMajor, &[]); + + let grid: Grid = Grid::new_with_order(3, 0, Order::ColumnMajor); + test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); } #[test] fn get() { - let grid = Grid::init(1, 2, 3); - assert_eq!(grid.get(0, 0), Some(&3)); + let grid = Grid::from_vec_with_order(vec![1, 2], 2, Order::RowMajor); + assert_eq!(grid.get(0, 1), Some(&2)); + } + + #[test] + fn get_column_major() { + let grid = Grid::from_vec_with_order(vec![1, 2], 1, Order::ColumnMajor); + assert_eq!(grid.get(1, 0), Some(&2)); } + #[test] fn get_none() { - let grid = Grid::init(1, 2, 3); + let grid = Grid::from_vec_with_order(vec![1, 2], 2, Order::RowMajor); assert_eq!(grid.get(1, 0), None); } + #[test] + fn get_none_column_major() { + let grid = Grid::from_vec_with_order(vec![1, 2], 1, Order::ColumnMajor); + assert_eq!(grid.get(0, 1), None); + } + #[test] fn get_mut() { - let mut grid = Grid::init(1, 2, 3); - let mut_ref = grid.get_mut(0, 0).unwrap(); - *mut_ref = 5; - assert_eq!(grid[0][0], 5); + let mut grid = Grid::from_vec_with_order(vec![1, 2], 2, Order::RowMajor); + assert_eq!(grid.get_mut(0, 1), Some(&mut 2)); + } + + #[test] + fn get_mut_column_major() { + let mut grid = Grid::from_vec_with_order(vec![1, 2], 1, Order::ColumnMajor); + assert_eq!(grid.get_mut(1, 0), Some(&mut 2)); } #[test] fn get_mut_none() { - let mut grid = Grid::init(1, 2, 3); - let mut_ref = grid.get_mut(1, 4); - assert_eq!(mut_ref, None); + let mut grid = Grid::from_vec_with_order(vec![1, 2], 2, Order::RowMajor); + assert_eq!(grid.get_mut(1, 0), None); } #[test] - fn idx() { - let grid: Grid = Grid::from_vec(vec![1, 2, 3, 4], 2); - assert_eq!(grid[0][0], 1); - assert_eq!(grid[0][1], 2); - assert_eq!(grid[1][0], 3); - assert_eq!(grid[1][1], 4); + fn get_mut_none_column_major() { + let mut grid = Grid::from_vec_with_order(vec![1, 2], 1, Order::ColumnMajor); + assert_eq!(grid.get_mut(0, 1), None); } #[test] @@ -1886,13 +2702,6 @@ mod test { assert_eq!(grid[(1, 1)], 4); } - #[test] - #[should_panic] - fn idx_panic_1() { - let grid = Grid::init(1, 2, 3); - let _ = grid[20][0]; - } - #[test] #[should_panic] fn idx_tup_panic_1() { @@ -1900,13 +2709,6 @@ mod test { let _ = grid[(20, 0)]; } - #[test] - #[should_panic] - fn idx_panic_2() { - let grid = Grid::init(1, 2, 3); - let _ = grid[0][20]; - } - #[test] #[should_panic] fn idx_tup_panic_2() { @@ -1914,13 +2716,6 @@ mod test { let _ = grid[(0, 20)]; } - #[test] - fn idx_set() { - let mut grid = Grid::init(1, 2, 3); - grid[0][0] = 4; - assert_eq!(grid[0][0], 4); - } - #[test] fn idx_tup_set() { let mut grid = Grid::init(1, 2, 3); @@ -1936,24 +2731,23 @@ mod test { #[test] fn transpose() { - let grid: Grid = grid![[1,2,3][4,5,6]]; - assert_eq!(format!("{:?}", grid.transpose()), "[[1, 4][2, 5][3, 6]]"); + let mut grid: Grid = grid![[1,2,3][4,5,6]]; + grid.transpose(); + assert_eq!(grid, grid![[1,4][2,5][3,6]]); } #[test] fn fill() { let mut grid: Grid = grid![[1,2,3][4,5,6]]; grid.fill(7); - assert_eq!(grid[0], [7, 7, 7]); - assert_eq!(grid[1], [7, 7, 7]); + test_grid(&grid, 2, 3, Order::RowMajor, &[7, 7, 7, 7, 7, 7]); } #[test] fn fill_with() { let mut grid: Grid = grid![[1,2,3][4,5,6]]; grid.fill_with(Default::default); - assert_eq!(grid[0], [0, 0, 0]); - assert_eq!(grid[1], [0, 0, 0]); + test_grid(&grid, 2, 3, Order::RowMajor, &[0, 0, 0, 0, 0, 0]); } #[test] @@ -1984,34 +2778,161 @@ mod test { let sum_by_col: Vec = grid.iter_cols().map(|col| col.sum()).collect(); assert_eq!(sum_by_col, vec![1 + 4, 2 + 5, 3 + 6]); } - #[test] - fn remove_col() { - let mut grid = grid![[1,2,3,4][5,6,7,8][9,10,11,12][13,14,15,16]]; - assert_eq![grid.remove_col(3), Some(vec![4, 8, 12, 16])]; - assert_eq![grid.remove_col(0), Some(vec![1, 5, 9, 13])]; - assert_eq![grid.remove_col(1), Some(vec![3, 7, 11, 15])]; - assert_eq![grid.remove_col(0), Some(vec![2, 6, 10, 14])]; - assert_eq![grid.remove_col(0), None]; - } + #[test] fn remove_row() { let mut grid = grid![[1,2][3,4][5,6]]; assert_eq![grid.remove_row(1), Some(vec![3, 4])]; + test_grid(&grid, 2, 2, Order::RowMajor, &[1, 2, 5, 6]); assert_eq![grid.remove_row(0), Some(vec![1, 2])]; + test_grid(&grid, 1, 2, Order::RowMajor, &[5, 6]); assert_eq![grid.remove_row(0), Some(vec![5, 6])]; + test_grid(&grid, 0, 0, Order::RowMajor, &[]); assert_eq![grid.remove_row(0), None]; + test_grid(&grid, 0, 0, Order::RowMajor, &[]); } + #[test] fn remove_row_out_of_bound() { let mut grid = grid![[1, 2][3, 4]]; assert_eq![grid.remove_row(5), None]; + test_grid(&grid, 2, 2, Order::RowMajor, &[1, 2, 3, 4]); + assert_eq![grid.remove_row(1), Some(vec![3, 4])]; + test_grid(&grid, 1, 2, Order::RowMajor, &[1, 2]); + } + + #[test] + fn remove_row_column_major() { + let mut grid = Grid::from_vec_with_order(vec![1, 3, 5, 2, 4, 6], 2, Order::ColumnMajor); + assert_eq![grid.remove_row(1), Some(vec![3, 4])]; + test_grid(&grid, 2, 2, Order::ColumnMajor, &[1, 5, 2, 6]); + assert_eq![grid.remove_row(0), Some(vec![1, 2])]; + test_grid(&grid, 1, 2, Order::ColumnMajor, &[5, 6]); + assert_eq![grid.remove_row(0), Some(vec![5, 6])]; + test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); + assert_eq![grid.remove_row(0), None]; + test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); + } + + #[test] + fn remove_row_out_of_bound_column_major() { + let mut grid = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor); + assert_eq![grid.remove_row(5), None]; + test_grid(&grid, 2, 2, Order::ColumnMajor, &[1, 3, 2, 4]); assert_eq![grid.remove_row(1), Some(vec![3, 4])]; + test_grid(&grid, 1, 2, Order::ColumnMajor, &[1, 2]); + } + + #[test] + fn remove_col() { + let mut grid = grid![[1,2,3,4][5,6,7,8][9,10,11,12][13,14,15,16]]; + assert_eq![grid.remove_col(3), Some(vec![4, 8, 12, 16])]; + let expected = [1, 2, 3, 5, 6, 7, 9, 10, 11, 13, 14, 15]; + test_grid(&grid, 4, 3, Order::RowMajor, &expected); + assert_eq![grid.remove_col(0), Some(vec![1, 5, 9, 13])]; + test_grid(&grid, 4, 2, Order::RowMajor, &[2, 3, 6, 7, 10, 11, 14, 15]); + assert_eq![grid.remove_col(1), Some(vec![3, 7, 11, 15])]; + test_grid(&grid, 4, 1, Order::RowMajor, &[2, 6, 10, 14]); + assert_eq![grid.remove_col(0), Some(vec![2, 6, 10, 14])]; + test_grid(&grid, 0, 0, Order::RowMajor, &[]); + assert_eq![grid.remove_col(0), None]; + test_grid(&grid, 0, 0, Order::RowMajor, &[]); } + #[test] fn remove_col_out_of_bound() { let mut grid = grid![[1, 2][3, 4]]; assert_eq!(grid.remove_col(5), None); + test_grid(&grid, 2, 2, Order::RowMajor, &[1, 2, 3, 4]); assert_eq!(grid.remove_col(1), Some(vec![2, 4])); + test_grid(&grid, 2, 1, Order::RowMajor, &[1, 3]); + } + + #[test] + fn remove_col_column_major() { + let internal = vec![1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15, 4, 8, 12, 16]; + let mut grid = Grid::from_vec_with_order(internal, 4, Order::ColumnMajor); + assert_eq![grid.remove_col(3), Some(vec![4, 8, 12, 16])]; + let expected = [1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15]; + test_grid(&grid, 4, 3, Order::ColumnMajor, &expected); + assert_eq![grid.remove_col(0), Some(vec![1, 5, 9, 13])]; + let expected = [2, 6, 10, 14, 3, 7, 11, 15]; + test_grid(&grid, 4, 2, Order::ColumnMajor, &expected); + assert_eq![grid.remove_col(1), Some(vec![3, 7, 11, 15])]; + test_grid(&grid, 4, 1, Order::ColumnMajor, &[2, 6, 10, 14]); + assert_eq![grid.remove_col(0), Some(vec![2, 6, 10, 14])]; + test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); + assert_eq![grid.remove_col(0), None]; + test_grid(&grid, 0, 0, Order::ColumnMajor, &[]); + } + + #[test] + fn remove_col_out_of_bound_column_major() { + let mut grid = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor); + assert_eq!(grid.remove_col(5), None); + test_grid(&grid, 2, 2, Order::ColumnMajor, &[1, 3, 2, 4]); + assert_eq!(grid.remove_col(1), Some(vec![2, 4])); + test_grid(&grid, 2, 1, Order::ColumnMajor, &[1, 3]); + } + + #[test] + fn flip_cols() { + let mut grid = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::RowMajor); + grid.flip_cols(); + test_grid(&grid, 2, 2, Order::RowMajor, &[2, 1, 4, 3]); + } + + #[test] + fn flip_cols_column_major() { + let mut grid = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor); + grid.flip_cols(); + test_grid(&grid, 2, 2, Order::ColumnMajor, &[2, 4, 1, 3]); + } + + #[test] + fn flip_rows() { + let mut grid = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::RowMajor); + grid.flip_rows(); + test_grid(&grid, 2, 2, Order::RowMajor, &[3, 4, 1, 2]); + } + + #[test] + fn flip_rows_column_major() { + let mut grid = Grid::from_vec_with_order(vec![1, 3, 2, 4], 2, Order::ColumnMajor); + grid.flip_rows(); + test_grid(&grid, 2, 2, Order::ColumnMajor, &[3, 1, 4, 2]); + } + + #[test] + fn rotate_left() { + let mut grid = Grid::from_vec_with_order(vec![1, 2, 3, 4, 5, 6], 3, Order::RowMajor); + grid.rotate_left(); + test_grid(&grid, 3, 2, Order::ColumnMajor, &[3, 2, 1, 6, 5, 4]); + assert_eq!(grid, grid![[3,6][2,5][1,4]]); + } + + #[test] + fn rotate_left_column_major() { + let mut grid = Grid::from_vec_with_order(vec![1, 4, 2, 5, 3, 6], 3, Order::ColumnMajor); + grid.rotate_left(); + test_grid(&grid, 3, 2, Order::RowMajor, &[3, 6, 2, 5, 1, 4]); + assert_eq!(grid, grid![[3,6][2,5][1,4]]); + } + + #[test] + fn rotate_right() { + let mut grid = Grid::from_vec_with_order(vec![1, 2, 3, 4, 5, 6], 3, Order::RowMajor); + grid.rotate_right(); + test_grid(&grid, 3, 2, Order::ColumnMajor, &[4, 5, 6, 1, 2, 3]); + assert_eq!(grid, grid![[4,1][5,2][6,3]]); + } + + #[test] + fn rotate_right_column_major() { + let mut grid = Grid::from_vec_with_order(vec![1, 4, 2, 5, 3, 6], 3, Order::ColumnMajor); + grid.rotate_right(); + test_grid(&grid, 3, 2, Order::RowMajor, &[4, 1, 5, 2, 6, 3]); + assert_eq!(grid, grid![[4,1][5,2][6,3]]); } #[cfg(feature = "serde")] @@ -2022,7 +2943,7 @@ mod test { fn serialize() { let grid: Grid = grid![[1, 2][3, 4]]; let s = serde_json::to_string(&grid).unwrap(); - println!("{s}"); + assert_eq!(s, r#"{"cols":2,"data":[1,2,3,4],"order":"RowMajor"}"#); } #[test] @@ -2031,5 +2952,12 @@ mod test { let grid: Grid = serde_json::from_str(&s).unwrap(); assert_eq!(grid, grid![[1, 2][3, 4]]); } + + #[test] + fn deserialize_with_order() { + let s = "{ \"cols\": 2, \"data\": [1, 3, 2, 4], \"order\": \"ColumnMajor\" }"; + let grid: Grid = serde_json::from_str(&s).unwrap(); + test_grid(&grid, 2, 2, Order::ColumnMajor, &[1, 3, 2, 4]); + } } }