From 3658b167c5d88245e7c4739962190726dfe9b1f1 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 | 1657 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 1247 insertions(+), 410 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index cdcbc66..b9fc81c 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. @@ -25,9 +25,9 @@ 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 +41,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 +120,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 order of data inside the internal vector 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 +213,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 +225,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 +246,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 +262,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 +277,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 +307,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,28 +319,48 @@ 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. /// /// # 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. @@ -252,22 +369,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, } } @@ -297,7 +429,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 +454,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 +485,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 +498,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. @@ -399,6 +556,8 @@ impl Grid { } /// Clears the grid. + /// + /// This doesn't change the grid order. pub fn clear(&mut self) { self.rows = 0; self.cols = 0; @@ -450,13 +609,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 +635,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 +674,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,22 +700,25 @@ 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), } } @@ -566,10 +743,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 +762,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: @@ -611,6 +791,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(); @@ -631,8 +817,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: @@ -659,9 +845,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 { @@ -683,7 +871,13 @@ impl Grid { 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; @@ -706,15 +900,25 @@ impl Grid { 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. @@ -735,9 +939,11 @@ impl Grid { 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; @@ -763,12 +969,20 @@ impl Grid { 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,10 +997,7 @@ 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]]); /// ``` /// /// # Panics @@ -808,8 +1019,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,9 +1045,7 @@ 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]]) /// ``` /// /// # Panics @@ -848,9 +1067,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 +1085,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 /// ``` @@ -874,55 +1101,95 @@ 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 changes the grid order. + 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]]) + /// ``` + 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()); + 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. + /// + /// # Examples + /// + /// ``` + /// use grid::*; + /// let mut grid = grid![[1,2][3,4]]; + /// grid.rotate_left(); + /// assert_eq!(grid, grid![[2,4][1,3]]); + /// ``` + pub fn rotate_left(&mut self) { + self.transpose(); + self.flip_rows(); } /// Rotate the grid 90° clockwise. @@ -931,25 +1198,13 @@ impl Grid { /// /// ``` /// 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, - } + pub fn rotate_right(&mut self) { + self.transpose(); + self.flip_cols(); } /// Rotate the grid 180°. @@ -958,20 +1213,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,8 +1229,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 +1253,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,28 +1313,11 @@ 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; @@ -1101,7 +1329,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 +1343,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 +1391,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 +1418,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 +1457,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] - fn insert_col_at_end() { - let mut grid: Grid = Grid::from_vec(vec![1, 2, 3, 4], 2); - grid.insert_col(2, vec![5, 6]); - assert_eq!(grid[0], [1, 2, 5]); - assert_eq!(grid[1], [3, 4, 6]); + #[should_panic] + fn from_vec_panics_1() { + let _: Grid = Grid::from_vec(vec![1, 2, 3], 0); } #[test] #[should_panic] - fn insert_col_out_of_idx() { - let mut grid: Grid = Grid::from_vec(vec![1, 2, 3, 4], 2); - grid.insert_col(3, vec![4, 5]); + fn from_vec_panics_2() { + let _: Grid = Grid::from_vec(vec![1, 2, 3], 2); } #[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 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 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 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 insert_col_empty() { - let mut grid: Grid = grid![]; - grid.insert_col(0, vec![1, 2, 3]); - assert_eq!(grid[0], [1]); - assert_eq!((3, 1), grid.size()); + 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 insert_row_out_of_idx() { - let mut grid: Grid = Grid::from_vec(vec![1, 2, 3, 4], 2); - grid.insert_row(3, vec![4, 5]); + 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 insert_row_wrong_size_of_idx() { - let mut grid: Grid = Grid::from_vec(vec![1, 2, 3, 4], 2); - grid.insert_row(1, vec![4, 5, 4]); + fn from_vec_with_order_panics_2() { + let _: Grid = Grid::from_vec_with_order(vec![1, 2, 3], 2, Order::ColumnMajor); } #[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); + 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 pop_col_1x3() { - let mut grid: Grid = Grid::from_vec(vec![1, 2, 3], 3); - assert_eq!(grid.pop_col(), Some(vec![3])); - assert_eq!(grid.size(), (1, 2)); + fn insert_col_at_end() { + let mut grid: Grid = Grid::from_vec_with_order(vec![1, 2, 3, 4], 2, Order::RowMajor); + grid.insert_col(2, vec![5, 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_with_order(vec![1, 2, 3, 4], 2, Order::RowMajor); + grid.insert_col(3, vec![4, 5]); + } + + #[test] + 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_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] + #[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]); + 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_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_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_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_with_order(vec![1, 2, 3], 3, Order::RowMajor); + assert_eq!(grid.pop_col(), Some(vec![3])); + 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 +1822,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 +1831,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 +1846,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 +1895,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 +1974,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 +2201,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 +2269,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 +2383,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 +2413,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 +2421,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 +2527,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 +2611,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 +2618,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 +2625,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 +2640,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 +2687,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 +2852,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 +2861,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]); + } } }