/// # Two Dimensional Grid /// /// The grid crate provides a basic 2D dynamic data structure. /// The purpose of this crate is to provide an universal data structure that is faster, /// uses less memory, and is easier to use than a naive `Vec>` solution. /// /// Similar to *C-like* arrays `grid` uses a flat 1D `Vec` data structure to have a continuos /// memory data layout. See also [this](https://stackoverflow.com/questions/17259877/1d-or-2d-array-whats-faster) /// explanation of why you should probably use a one-dimensional array approach. /// /// Note that this crate uses a [*row-major*](https://eli.thegreenplace.net/2015/memory-layout-of-multi-dimensional-arrays) memory layout. /// Therefore, `grid.push_row()` is way faster then the `grid.push_col()` operation. /// /// This crate will always provide a 2D data structure. If you need three or more dimensions take a look at the /// [ndarray crate](https://docs.rs/ndarray/0.13.0/ndarray/). The `grid` create is a container for all kind of data. /// If you need to perform matrix operations, you are better of with a linear algebra lib, such as /// [cgmath](https://docs.rs/cgmath/0.17.0/cgmath/) or [nalgebra](https://docs.rs/nalgebra/0.21.0/nalgebra/). /// /// No other dependencies except for the std lib are used. /// /// Most of the functions `std::Vec` offer are also implemented in `grid` and slightly modified for a 2D data object. use std::fmt; use std::iter::StepBy; use std::ops::Index; use std::ops::IndexMut; use std::slice::Iter; use std::slice::IterMut; /// Stores elements of a certain type in a 2D grid structure. pub struct Grid { data: Vec, cols: usize, rows: usize, } #[doc(hidden)] #[macro_export] macro_rules! count { () => (0usize); ( $x:tt $($xs:tt)* ) => (1usize + $crate::count!($($xs)*)); } /// Init a grid with values. /// ``` /// use grid::grid; /// let grid = grid![[1, 2, 3] /// [4, 5, 6] /// [7, 8, 9]]; /// assert_eq!(grid.size(), (3, 3)) /// ``` #[macro_export] macro_rules! grid { () => { $crate::Grid::from_vec(vec![], 0) }; ( [$( $x:expr ),* ]) => { { let vec = vec![$($x),*]; let len = vec.len(); $crate::Grid::from_vec(vec, len) } }; ( [$( $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 mut vec = Vec::with_capacity(rows * cols); $( vec.push($x0); )* $( $( vec.push($x); )* )* $crate::Grid::from_vec(vec, cols) } }; } impl Grid { /// Init a grid of size rows x columns with default values of the given type. /// For example this will generate a 2x3 grid of zeros: /// ``` /// use grid::Grid; /// let grid : Grid = Grid::new(2,2); /// assert_eq!(grid[0][0], 0); /// ``` pub fn new(rows: usize, cols: usize) -> Grid where T: Default, { if rows < 1 || cols < 1 { panic!("Grid size of rows and columns must be greater than zero."); } Grid { data: vec![T::default(); rows * cols], cols: cols, rows: rows, } } /// Init a grid of size rows x columns with the given data element. pub fn init(rows: usize, cols: usize, data: T) -> Grid { if rows < 1 || cols < 1 { panic!("Grid size of rows and columns must be greater than zero."); } Grid { data: vec![data; rows * cols], cols: cols, rows: rows, } } /// Returns a grid from a vector with a given column length. /// The length of `vec` must be a multiple of `cols`. /// /// For example: /// /// ``` /// use grid::Grid; /// let grid = Grid::from_vec(vec![1,2,3,4,5,6], 3); /// assert_eq!(grid.size(), (2, 3)); /// ``` /// /// will create a grid with the following layout: /// [1,2,3] /// [4,5,6] /// /// This example will fail, because `vec.len()` is not a multiple of `cols`: /// /// ``` should_panic /// use grid::Grid; /// Grid::from_vec(vec![1,2,3,4,5], 3); /// ``` pub fn from_vec(vec: Vec, cols: usize) -> Grid { let rows = vec.len(); if rows == 0 { if cols == 0 { return Grid { data: vec![], rows: 0, cols: 0, }; } else { panic!("Vector length is zero, but cols is {:?}", cols); } } else if rows % cols != 0 { panic!("Vector length must be a multiple of cols."); } else { Grid { data: vec, rows: rows / cols, cols: cols, } } } /// Returns a reference to an element, without performing bound checks. /// Generally not recommended, use with caution! /// Calling this method with an out-of-bounds index is undefined behavior even if the resulting reference is not used. #[inline] pub unsafe fn get_unchecked(&self, row: usize, col: usize) -> &T { self.data.get_unchecked(row * self.cols() + col) } /// Returns a mutable reference to an element, without performing bound checks. /// Generally not recommended, use with caution! /// Calling this method with an out-of-bounds index is undefined behavior even if the resulting reference is not used. #[inline] pub unsafe fn get_unchecked_mut(&mut self, row: usize, col: usize) -> &mut T { let cols = self.cols; self.data.get_unchecked_mut(row * cols + col) } /// Access a certain element in the grid. /// Returns None if an element beyond the grid bounds is tried to be accessed. pub fn get(&self, row: usize, col: usize) -> Option<&T> { if row < self.rows && col < self.cols { unsafe { Some(self.get_unchecked(row, col)) } } else { None } } /// Mutable access to a certain element in the grid. /// Returns None if an element beyond the grid bounds is tried to be accessed. pub fn get_mut(&mut self, row: usize, col: usize) -> Option<&mut T> { if row < self.rows && col < self.cols { unsafe { Some(self.get_unchecked_mut(row, col)) } } else { None } } /// Returns the size of the gird as a two element tuple. /// First element are the number of rows and the second the columns. pub fn size(&self) -> (usize, usize) { (self.rows, self.cols) } /// Returns the number of rows of the grid. pub fn rows(&self) -> usize { self.rows } /// Returns the number of columns of the grid. pub fn cols(&self) -> usize { self.cols } /// Returns true if the grid contains no elements. /// For example: /// ``` /// use grid::*; /// let grid : Grid = grid![]; /// assert!(grid.is_empty()); /// ``` pub fn is_empty(&self) -> bool { self.cols == 0 && self.rows == 0 } /// Clears the grid. pub fn clear(&mut self) { self.rows = 0; self.cols = 0; self.data.clear(); } /// Returns an iterator over the whole grid, starting from the first row and column. /// ``` /// use grid::*; /// let grid: Grid = grid![[1,2][3,4]]; /// let mut iter = grid.iter(); /// assert_eq!(iter.next(), Some(&1)); /// assert_eq!(iter.next(), Some(&2)); /// assert_eq!(iter.next(), Some(&3)); /// assert_eq!(iter.next(), Some(&4)); /// assert_eq!(iter.next(), None); /// ``` pub fn iter(&self) -> Iter { self.data.iter() } /// Returns an mutable iterator over the whole grid that allows modifying each value. /// ``` /// use grid::*; /// let mut grid: Grid = grid![[1,2][3,4]]; /// let mut iter = grid.iter_mut(); /// let next = iter.next(); /// assert_eq!(next, Some(&mut 1)); /// *next.unwrap() = 10; /// ``` pub fn iter_mut(&mut self) -> IterMut { self.data.iter_mut() } /// Returns an iterator over a column. /// /// # Examples /// /// ``` /// use grid::*; /// let grid: Grid = grid![[1, 2, 3][3, 4, 5]]; /// let mut col_iter = grid.iter_col(1); /// assert_eq!(col_iter.next(), Some(&2)); /// assert_eq!(col_iter.next(), Some(&4)); /// assert_eq!(col_iter.next(), None); /// ``` /// /// # Panics /// /// 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); } else { panic!( "out of bounds. Column must be less than {:?}, but is {:?}.", self.cols, col ) } } /// Returns a mutable iterator over a column. /// /// # Examples /// /// ``` /// use grid::*; /// let mut grid: Grid = grid![[1, 2, 3][3, 4, 5]]; /// let mut col_iter = grid.iter_col_mut(1); /// let next = col_iter.next(); /// assert_eq!(next, Some(&mut 2)); /// *next.unwrap() = 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); } else { panic!( "out of bounds. Column must be less than {:?}, but is {:?}.", self.cols, col ) } } /// Returns an iterator over a row. /// /// # Examples /// /// ``` /// use grid::*; /// let grid: Grid = grid![[1, 2, 3][3, 4, 5]]; /// let mut col_iter = grid.iter_row(1); /// assert_eq!(col_iter.next(), Some(&3)); /// assert_eq!(col_iter.next(), Some(&4)); /// assert_eq!(col_iter.next(), Some(&5)); /// assert_eq!(col_iter.next(), None); /// ``` /// /// # 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; return self.data[start..(start + self.cols)].iter(); } else { panic!( "out of bounds. Row must be less than {:?}, but is {:?}.", self.rows, row ) } } /// Returns a mutable iterator over a row. /// /// # Examples /// /// ``` /// use grid::*; /// let mut grid: Grid = grid![[1, 2, 3][3, 4, 5]]; /// let mut col_iter = grid.iter_row_mut(1); /// let next = col_iter.next(); /// *next.unwrap() = 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; return self.data[start..(start + cols)].iter_mut(); } else { panic!( "out of bounds. Row must be less than {:?}, but is {:?}.", self.rows, row ) } } /// Add a new row to the grid. /// /// # Examples /// /// ``` /// use grid::*; /// let mut grid: Grid = grid![[1, 2, 3][3, 4, 5]]; /// 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); /// ``` /// /// Can also be used to init an empty grid: /// /// ``` /// use grid::*; /// let mut grid: Grid = grid![]; /// let row = vec![1,2,3]; /// grid.push_row(row); /// assert_eq!(grid.size(), (1, 3)); /// ``` /// /// # Panics /// /// Panics if the grid is not empty and `row.len() != grid.cols()`. pub fn push_row(&mut self, row: Vec) { let input_row_len = row.len(); if self.rows > 0 && input_row_len != self.cols { panic!( "pushed row does not match. Length must be {:?}, but was {:?}.", self.cols, input_row_len ) } self.data.extend(row); self.rows += 1; self.cols = input_row_len; } /// Add a new column to the grid. /// /// *Important:* /// Please note that `Grid` uses a Row-Major memory layout. Therefore, the `push_col()` /// operation requires quite a lot of memory shifting and will be significantly slower compared /// to a `push_row()` operation. /// /// # Examples /// /// ``` /// use grid::*; /// let mut grid: Grid = grid![[1, 2, 3][3, 4, 5]]; /// 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); /// ``` /// /// Can also be used to init an empty grid: /// /// ``` /// use grid::*; /// let mut grid: Grid = grid![]; /// let col = vec![1,2,3]; /// grid.push_col(col); /// assert_eq!(grid.size(), (3, 1)); /// ``` /// /// # Panics /// /// Panics if the grid is not empty and `col.len() != grid.rows()`. pub fn push_col(&mut self, col: Vec) { let input_col_len = col.len(); if self.cols > 0 && input_col_len != self.rows { panic!( "pushed column does not match. Length must be {:?}, but was {:?}.", self.rows, input_col_len ) } self.data.reserve(col.len()); for (idx, d) in col.iter().enumerate() { let vec_idx = (idx + 1) * self.cols + idx; self.data.insert(vec_idx, d.to_owned()); } self.cols += 1; self.rows = input_col_len; } } impl Clone for Grid { fn clone(&self) -> Self { Grid { rows: self.rows, cols: self.cols, data: self.data.clone(), } } } impl Index for Grid { type Output = [T]; fn index(&self, idx: usize) -> &Self::Output { if idx < self.rows { let start_idx = idx * self.cols; &self.data[start_idx..start_idx + self.cols] } else { panic!( "index {:?} out of bounds. Grid has {:?} rows.", self.rows, idx ); } } } impl IndexMut for Grid { fn index_mut(&mut self, idx: usize) -> &mut Self::Output { &mut self.data[(idx * &self.cols)..] } } impl fmt::Debug for Grid { #[allow(unused_must_use)] fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "["); if self.cols > 0 { for (i, _) in self.data.iter().enumerate().step_by(self.cols) { write!(f, "{:?}", &self.data[i..(i + self.cols)]); } } write!(f, "]") } } #[cfg(test)] mod test { use super::*; #[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]; } #[test] fn push_col_small() { 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).map(|x| *x).collect::>(), vec![0, 1, 2, 3] ); assert_eq!( grid.iter_row(1).map(|x| *x).collect::>(), vec![10, 11, 12, 13] ); } #[test] fn push_col() { 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).map(|x| *x).collect::>(), vec!['a', 'b', 'c', 'd', 'x'] ); assert_eq!( grid.iter_row(1).map(|x| *x).collect::>(), vec!['a', 'b', 'c', 'd', 'y'] ); assert_eq!( grid.iter_row(2).map(|x| *x).collect::>(), vec!['a', 'b', 'c', 'd', 'z'] ); } #[test] fn push_col_single() { 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] 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] #[should_panic] fn push_col_wrong_size() { let mut grid: Grid = grid![['a','a','a']['a','a','a']]; grid.push_col(vec!['b']); grid.push_col(vec!['b', 'b']); } #[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] #[should_panic] fn push_row_wrong_size() { let mut grid: Grid = grid![['a','a','a']['a','a','a']]; 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); } #[test] #[should_panic] fn iter_row_empty() { let grid: Grid = grid![]; let _ = grid.iter_row(0); } #[test] #[should_panic] fn iter_row_out_of_bound() { let grid: Grid = grid![[1,2,3][1,2,3]]; let _ = grid.iter_row(2); } #[test] #[should_panic] fn iter_col_out_of_bound() { let grid: Grid = grid![[1,2,3][1,2,3]]; let _ = grid.iter_col(3); } #[test] #[should_panic] fn iter_col_zero() { let grid: Grid = grid![]; let _ = grid.iter_col(0); } #[test] fn iter() { let grid: Grid = grid![[1,2][3,4]]; let mut iter = grid.iter(); assert_eq!(iter.next(), Some(&1)); assert_eq!(iter.next(), Some(&2)); assert_eq!(iter.next(), Some(&3)); assert_eq!(iter.next(), Some(&4)); assert_eq!(iter.next(), None); } #[test] fn clear() { let mut grid: Grid = grid![[1, 2, 3]]; grid.clear(); assert!(grid.is_empty()); } #[test] fn is_empty_false() { let grid: Grid = grid![[1, 2, 3]]; assert!(!grid.is_empty()); } #[test] fn is_empty_true() { let grid: Grid = grid![]; assert!(grid.is_empty()); } #[test] fn fmt_empty() { let grid: Grid = grid![]; assert_eq!(format!("{:?}", grid), "[]"); } #[test] fn fmt_row() { let grid: Grid = grid![[1, 2, 3]]; assert_eq!(format!("{:?}", grid), "[[1, 2, 3]]"); } #[test] fn fmt_grid() { let grid: Grid = grid![[1,2,3][4,5,6][7,8,9]]; assert_eq!(format!("{:?}", grid), "[[1, 2, 3][4, 5, 6][7, 8, 9]]"); } #[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); } #[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] fn macro_init_2() { let grid = grid![[1, 2, 3] [4, 5, 6] [7, 8, 9]]; assert_eq!(grid.size(), (3, 3)) } #[test] fn macro_init_char() { let grid = grid![['a', 'b', 'c'] ['a', 'b', 'c'] ['a', 'b', 'c']]; assert_eq!(grid.size(), (3, 3)); assert_eq!(grid[1][1], 'b'); } #[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] fn macro_init_empty() { let grid: Grid = grid![]; assert_eq!(grid.size(), (0, 0)); } #[test] fn from_vec_zero() { let grid: Grid = Grid::from_vec(vec![], 0); assert_eq!(grid.size(), (0, 0)); } #[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] #[should_panic] fn from_vec_panics_3() { let _: Grid = Grid::from_vec(vec![], 1); } #[test] fn init() { Grid::init(1, 2, 3); Grid::init(1, 2, 1.2); Grid::init(1, 2, 'a'); } #[test] fn new() { let grid: Grid = Grid::new(1, 2); assert_eq!(grid[0][0], 0); } #[test] #[should_panic] fn init_panics() { Grid::init(0, 2, 3); } #[test] #[should_panic] fn ctr_panics_2() { Grid::init(1, 0, 3); } #[test] fn get() { let grid = Grid::init(1, 2, 3); assert_eq!(grid.get(0, 0), Some(&3)); } #[test] fn get_none() { let grid = Grid::init(1, 2, 3); assert_eq!(grid.get(1, 0), 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); } #[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); } #[test] fn idx() { let grid = Grid::init(1, 2, 3); assert_eq!(grid[0][0], 3); } #[test] #[should_panic] fn idx_panic_1() { let grid = Grid::init(1, 2, 3); grid[20][0]; } #[test] #[should_panic] fn idx_panic_2() { let grid = Grid::init(1, 2, 3); 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 size() { let grid = Grid::init(1, 2, 3); assert_eq!(grid.size(), (1, 2)); } }