From 15b08ddd5156661625e9e1e30ae298de986bdd0c 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 | 879 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 688 insertions(+), 191 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e153641..aea6207 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,5 @@ #![warn(clippy::all, clippy::pedantic)] - +// TODO: Update documentation /*! # Two Dimensional Grid Continuous growable 2D data structure. @@ -83,6 +83,7 @@ macro_rules! count { /// [4, 5] // This does not work! /// [7, 8, 9]]; /// ``` +// TODO: Add a way to change grid order #[macro_export] macro_rules! grid { () => { @@ -115,6 +116,23 @@ macro_rules! grid { }; } +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)] +// TODO: Document +pub enum Order { + #[default] + RowMajor, + 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. @@ -127,6 +145,7 @@ pub struct Grid { data: Vec, cols: usize, rows: usize, + order: Order, } impl Grid { @@ -143,21 +162,41 @@ impl Grid { /// /// # Panics /// - /// Panics if `rows * cols > usize`. - pub fn new(rows: usize, cols: usize) -> Grid + /// 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::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. @@ -166,22 +205,37 @@ impl Grid { /// /// # Panics /// - /// Panics if `rows * cols > usize`. - pub fn init(rows: usize, cols: usize, data: T) -> Grid + /// 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::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, } } @@ -211,7 +265,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, @@ -225,16 +290,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! /// @@ -244,7 +321,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. @@ -256,7 +334,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. @@ -313,6 +392,8 @@ impl Grid { } /// Clears the grid. + /// + /// This doesn't change the grid order. pub fn clear(&mut self) { self.rows = 0; self.cols = 0; @@ -364,13 +445,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. @@ -391,14 +478,19 @@ impl Grid { /// /// 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. @@ -418,15 +510,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), } } @@ -446,16 +542,19 @@ impl Grid { /// # 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), } } @@ -480,10 +579,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. @@ -525,6 +627,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(); @@ -573,9 +681,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 { @@ -593,11 +703,18 @@ impl Grid { /// assert_eq![grid.pop_row(), Some(vec![1,2,3])]; /// assert_eq![grid.pop_row(), None]; /// ``` + // TODO: test with new order 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; @@ -616,19 +733,30 @@ impl Grid { /// assert_eq![grid.remove_row(0), Some(vec![5,6])]; /// assert_eq![grid.remove_row(0), None]; /// ``` + // TODO: test with new order 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. @@ -645,13 +773,16 @@ impl Grid { /// assert_eq![grid.pop_col(), Some(vec![1,4])]; /// assert_eq![grid.pop_col(), None]; /// ``` + // TODO: test with new order 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; @@ -673,16 +804,25 @@ impl Grid { /// assert_eq![grid.remove_col(0), Some(vec![2,6,10,14])]; /// assert_eq![grid.remove_col(0), None]; /// ``` + // TODO: test with new order 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; @@ -708,6 +848,7 @@ impl Grid { /// Panics if: /// - the grid is not empty and `row.len() != grid.cols()`. /// - the index is greater than the number of rows + // TODO: test with new order pub fn insert_row(&mut self, index: usize, row: Vec) { let input_len = row.len(); assert!( @@ -722,8 +863,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; } @@ -748,6 +899,7 @@ impl Grid { /// Panics if: /// - the grid is not empty and `col.len() != grid.rows()`. /// - the index is greater than the number of columns + // TODO: test with new order pub fn insert_col(&mut self, index: usize, col: Vec) { let input_len = col.len(); assert!( @@ -762,9 +914,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; @@ -772,8 +932,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 grid order, which is + /// row-major by default. /// /// # Examples /// ``` @@ -788,28 +948,20 @@ 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()); - } - } - Grid { - data, - cols: self.rows, - rows: self.cols, - } + /// + /// This changes the grid order. + pub fn transpose(&mut self) { + self.order = self.order.counterpart(); + core::mem::swap(&mut self.rows, &mut self.cols); } /// Rotate the grid 90° counter-clockwise. @@ -821,6 +973,7 @@ impl Grid { /// let grid = grid![[1,2,3][4,5,6]]; /// assert_eq!(grid.rotate_left(), grid![[3,6][2,5][1,4]]); /// ``` + // TODO: Rework + document + test the change of order #[must_use] pub fn rotate_left(&self) -> Grid where @@ -836,6 +989,7 @@ impl Grid { data, cols: self.rows, rows: self.cols, + order: self.order, } } @@ -848,6 +1002,7 @@ impl Grid { /// let grid = grid![[1,2,3][4,5,6]]; /// assert_eq!(grid.rotate_right(), grid![[4,1][5,2][6,3]]); /// ``` + // TODO: Rework + document + test the change of order #[must_use] pub fn rotate_right(&self) -> Grid where @@ -863,6 +1018,7 @@ impl Grid { data, cols: self.rows, rows: self.cols, + order: self.order, } } @@ -872,20 +1028,12 @@ impl Grid { /// /// ``` /// 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,11 +1130,13 @@ impl Clone for Grid { rows: self.rows, cols: self.cols, data: self.data.clone(), + order: self.order, } } } impl Index for Grid { + // TODO: Rework type Output = [T]; #[inline] @@ -997,6 +1147,7 @@ impl Index for Grid { } impl IndexMut for Grid { + // TODO: Rework #[inline] fn index_mut(&mut self, idx: usize) -> &mut [T] { let start_idx = idx * self.cols; @@ -1015,7 +1166,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] } } @@ -1028,11 +1180,13 @@ 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 { + // TODO: Rework #[allow(unused_must_use)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "["); @@ -1084,7 +1238,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 } } @@ -1100,7 +1265,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(); @@ -1139,19 +1304,78 @@ 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] @@ -1333,57 +1557,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] @@ -1401,12 +1606,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] @@ -1424,44 +1685,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]]; @@ -1491,6 +1912,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]]; @@ -1696,44 +2135,63 @@ mod test { } #[test] - #[should_panic] - fn from_vec_panics_1() { - let _: Grid = Grid::from_vec(vec![1, 2, 3], 0); + fn init() { + 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 from_vec_panics_2() { - let _: Grid = Grid::from_vec(vec![1, 2, 3], 2); + fn init_panics() { + Grid::init(usize::MAX, 2, 3); } #[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 init_empty() { + let grid = Grid::init(0, 1, 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() { - Grid::init(1, 2, 3); - Grid::init(1, 2, 1.2); - Grid::init(1, 2, 'a'); + 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] - fn init_empty() { - let grid = Grid::init(0, 1, 0); - assert!(grid.is_empty()); - assert_eq!(grid.cols(), 0); - assert_eq!(grid.rows(), 0); + #[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] @@ -1745,41 +2203,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 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] @@ -1850,8 +2346,9 @@ 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]