From 21f84fc4680fc1bcdd16fa725e2e8e8f57700c3a Mon Sep 17 00:00:00 2001 From: Armin Becher Date: Thu, 2 Apr 2020 23:08:02 +0200 Subject: [PATCH] Add macro --- Cargo.toml | 2 - README.md | 2 +- benches/benches.rs | 4 +- src/lib.rs | 148 +++++++++++++++++++++++++++++++++++++-------- 4 files changed, 127 insertions(+), 29 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5eb16dd..c7667ab 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,8 +4,6 @@ version = "0.1.0" authors = ["Armin Becher "] edition = "2018" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dev-dependencies] criterion = "0.3.1" diff --git a/README.md b/README.md index a617cd9..43e7b4a 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ # Grid -Data structure grid for rust. Provide a two dimensional data storage that is easy to use and fast. +Data structure grid for rust. Provide a two dimensional data storage that is easy to use and fast. diff --git a/benches/benches.rs b/benches/benches.rs index 1d12f2a..4858b55 100644 --- a/benches/benches.rs +++ b/benches/benches.rs @@ -10,7 +10,7 @@ fn init_vec_flat(size: usize) -> Vec { } fn init_grid(size: usize) -> Grid { - Grid::new(size, size, 0) + Grid::init(size, size, 0) } fn get_vec_vec(x: usize, y: usize) -> u32 { @@ -48,7 +48,7 @@ fn set_grid(x: usize, y: usize) { } fn criterion_benchmark(c: &mut Criterion) { - // Init + // New c.bench_function("Init vec vec 10x10", |b| { b.iter(|| init_vec_vec(black_box(10))) }); diff --git a/src/lib.rs b/src/lib.rs index 7cf2f4d..979b0e7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,28 +3,94 @@ use std::ops::IndexMut; pub struct Grid { data: Vec, - columns: usize, + cols: usize, rows: usize, } +#[allow(unused_macros)] +macro_rules! count { + () => (0usize); + ( $x:tt $($xs:tt)* ) => (1usize + count!($($xs)*)); +} + +#[macro_export] +macro_rules! grid { + () => { + Grid { + rows: 0, + cols: 0, + data: vec![], + } + }; + ( [$( $x:expr ),* ]) => { { + let vec = vec![$($x),*]; + Grid { rows : 1, cols: vec.len(), data: vec } + } }; + ( [$( $x0:expr ),*] $($( $x:expr ),*);* ) => { + { + let mut _assert_width0 = [(); count!($($x0)*)]; + let mut vec = Vec::new(); + let rows = 1usize; + let cols = count!($($x0)*); + + $( vec.push($x0); )* + + $( + let rows = rows + 1usize; + let _assert_width = [(); count!($($x)*)]; + _assert_width0 = _assert_width; + $( vec.push($x); )* + )* + + Grid { rows : rows, cols: cols, data: vec } + } + }; +} + impl Grid { - pub fn new(rows: usize, columns: usize, data: T) -> Grid { - if rows < 1 || columns < 1 { + /// 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![data; rows * columns], - columns: columns, + data: vec![T::default(); rows * cols], + cols: cols, rows: rows, } } - pub fn get(&self, row: usize, column: usize) -> Option<&T> { - self.data.get(row * self.columns + column % self.columns) + /// 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, + } } + /// 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, column: usize) -> Option<&T> { + self.data.get(row * self.cols + column % self.cols) + } + + /// 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.columns) + (self.rows, self.cols) } } @@ -38,7 +104,7 @@ impl Index for Grid { self.rows, idx ); } - &self.data[(idx * &self.columns)..] + &self.data[(idx * &self.cols)..] } } @@ -50,7 +116,7 @@ impl IndexMut for Grid { self.rows, idx ); } - &mut self.data[(idx * &self.columns)..] + &mut self.data[(idx * &self.cols)..] } } @@ -59,64 +125,98 @@ mod test { use super::*; #[test] - fn ctr() { - Grid::new(1, 2, 3); - Grid::new(1, 2, 1.2); - Grid::new(1, 2, 'a'); + fn macro_init() { + //TODO let grid = grid![[1, 2, 3][4, 5, 6]]; + 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_one_row() { + let grid: Grid = grid![[1, 2, 3, 4]]; + assert_eq!(grid.size(), (1, 0)); + 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 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 ctr_panics() { - Grid::new(0, 2, 3); + fn init_panics() { + Grid::init(0, 2, 3); } #[test] #[should_panic] fn ctr_panics_2() { - Grid::new(1, 0, 3); + Grid::init(1, 0, 3); } #[test] fn get() { - let grid = Grid::new(1, 2, 3); + let grid = Grid::init(1, 2, 3); assert_eq!(grid.get(0, 0), Some(&3)); } #[test] fn get_none() { - let grid = Grid::new(1, 2, 3); + let grid = Grid::init(1, 2, 3); assert_eq!(grid.get(1, 0), None); } #[test] fn idx() { - let grid = Grid::new(1, 2, 3); + let grid = Grid::init(1, 2, 3); assert_eq!(grid[0][0], 3); } #[test] #[should_panic] fn idx_panic_1() { - let grid = Grid::new(1, 2, 3); + let grid = Grid::init(1, 2, 3); grid[20][0]; } #[test] #[should_panic] fn idx_panic_2() { - let grid = Grid::new(1, 2, 3); + let grid = Grid::init(1, 2, 3); grid[0][20]; } #[test] fn idx_set() { - let mut grid = Grid::new(1, 2, 3); + let mut grid = Grid::init(1, 2, 3); grid[0][0] = 4; assert_eq!(grid[0][0], 4); } #[test] fn size() { - let grid = Grid::new(1, 2, 3); + let grid = Grid::init(1, 2, 3); assert_eq!(grid.size(), (1, 2)); } }