diff --git a/benches/benches.rs b/benches/benches.rs index 5b9e9db..d31acac 100644 --- a/benches/benches.rs +++ b/benches/benches.rs @@ -201,6 +201,60 @@ fn criterion_benchmark(c: &mut Criterion) { criterion::BatchSize::SmallInput, ) }); + + // Insert + c.bench_function("grid_insert_row", |b| { + let grid = init_grid(); + b.iter_batched( + || grid.clone(), + |mut g| g.insert_row(rand(), vec![42; g.cols()]), + criterion::BatchSize::SmallInput, + ) + }); + c.bench_function("grid_insert_col", |b| { + let grid = init_grid(); + b.iter_batched( + || grid.clone(), + |mut g| g.insert_col(rand(), vec![42; g.rows()]), + criterion::BatchSize::SmallInput, + ) + }); + + // Expand + c.bench_function("grid_expand_rows", |b| { + let grid = init_grid(); + b.iter_batched( + || grid.clone(), + |mut g| g.expand_rows(1), + criterion::BatchSize::SmallInput, + ) + }); + c.bench_function("grid_expand_cols", |b| { + let grid = init_grid(); + b.iter_batched( + || grid.clone(), + |mut g| g.expand_cols(1), + criterion::BatchSize::SmallInput, + ) + }); + + // Prepend + c.bench_function("grid_prepend_rows", |b| { + let grid = init_grid(); + b.iter_batched( + || grid.clone(), + |mut g| g.prepend_rows(1), + criterion::BatchSize::SmallInput, + ) + }); + c.bench_function("grid_prepend_cols", |b| { + let grid = init_grid(); + b.iter_batched( + || grid.clone(), + |mut g| g.prepend_cols(1), + criterion::BatchSize::SmallInput, + ) + }); } criterion_group!(benches, criterion_benchmark); diff --git a/src/lib.rs b/src/lib.rs index 297c395..f68e4f8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1698,6 +1698,100 @@ impl Grid { self.cols += cols; } } + + /// Expands the grid by inserting a given amount of rows at the beginning, filling the new rows with `T::default()`. + /// If the grid has no rows or no columns, nothing will happen. + /// + /// # Examples + /// + /// ``` + /// use grid::*; + /// let mut grid: Grid = grid![[1, 2, 3][3, 4, 5]]; + /// grid.prepend_rows(2); + /// assert_eq!(grid.rows(), 4); + /// assert_eq!(grid[(0, 0)], 0); + /// assert_eq!(grid[(0, 1)], 0); + /// assert_eq!(grid[(0, 2)], 0); + /// assert_eq!(grid[(1, 0)], 0); + /// assert_eq!(grid[(1, 1)], 0); + /// assert_eq!(grid[(1, 2)], 0); + /// ``` + /// + /// # Performance + /// + /// This method will be significantly slower if the grid uses a column-major memory layout. + pub fn prepend_rows(&mut self, rows: usize) { + if rows > 0 && self.cols > 0 { + self.data + .resize_with(self.data.len() + rows * self.cols, T::default); + + match self.order { + Order::RowMajor => { + for i in (0..self.rows).rev() { + let s = i * self.cols; + let e = (i + rows + 1) * self.cols; + self.data[s..e].rotate_left(self.cols); + } + } + Order::ColumnMajor => { + for row_added in 0..rows { + for i in (0..self.cols).rev() { + let total_rows = self.rows + row_added; + let col_idx = i * total_rows; + self.data[col_idx..=col_idx + total_rows + i].rotate_right(i + 1); + } + } + } + } + self.rows += rows; + } + } + + /// Expands the grid by inserting a given amount of columns at the beginning, filling the new columns with `T::default()`. + /// If the grid has no rows or no columns, nothing will happen. + /// + /// # Examples + /// + /// ``` + /// use grid::*; + /// let mut grid: Grid = grid![[1, 2, 3][3, 4, 5]]; + /// grid.prepend_cols(2); + /// assert_eq!(grid.cols(), 5); + /// assert_eq!(grid[(0, 0)], 0); + /// assert_eq!(grid[(0, 1)], 0); + /// assert_eq!(grid[(1, 0)], 0); + /// assert_eq!(grid[(1, 1)], 0); + /// ``` + /// + /// # Performance + /// + /// This method will be significantly slower if the grid uses a row-major memory layout. + pub fn prepend_cols(&mut self, cols: usize) { + if cols > 0 && self.rows > 0 { + self.data + .resize_with(self.data.len() + cols * self.rows, T::default); + + match self.order { + Order::RowMajor => { + for col_added in 0..cols { + for i in (0..self.rows).rev() { + let total_cols = self.cols + col_added; + let row_idx = i * total_cols; + self.data[row_idx..=row_idx + total_cols + i].rotate_right(i + 1); + } + } + } + Order::ColumnMajor => { + for i in (0..self.cols).rev() { + let s = i * self.rows; + let e = (i + cols + 1) * self.rows; + self.data[s..e].rotate_left(self.rows); + } + } + } + self.cols += cols; + } + } } impl Default for Grid { @@ -2757,6 +2851,102 @@ mod test { assert_eq!(grid.into_vec(), Vec::::new()); } + #[test] + fn prepend_rows() { + let mut grid = Grid::from_vec_with_order(vec![1, 1, 1, 2, 2, 2], 3, Order::RowMajor); + grid.prepend_rows(2); + + assert_eq!(grid.size(), (4, 3)); + assert_eq!(grid.order, Order::RowMajor); + assert_eq!(grid.rows(), 4); + assert_eq!(grid.cols(), 3); + assert_eq!(grid.into_vec(), vec![0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2]); + } + + #[test] + fn prepend_rows_column_major() { + let mut grid = Grid::from_vec_with_order(vec![1, 2, 1, 2, 1, 2], 3, Order::ColumnMajor); + grid.prepend_rows(2); + + assert_eq!(grid.size(), (4, 3)); + assert_eq!(grid.order, Order::ColumnMajor); + assert_eq!(grid.rows(), 4); + assert_eq!(grid.cols(), 3); + assert_eq!(grid.into_vec(), vec![0, 0, 1, 2, 0, 0, 1, 2, 0, 0, 1, 2]); + } + + #[test] + fn prepend_rows_zero() { + let mut grid = Grid::from_vec_with_order(vec![1, 1, 1], 3, Order::RowMajor); + grid.prepend_rows(0); + + assert_eq!(grid.size(), (1, 3)); + assert_eq!(grid.order, Order::RowMajor); + assert_eq!(grid.rows(), 1); + assert_eq!(grid.cols(), 3); + assert_eq!(grid.into_vec(), vec![1, 1, 1]); + } + + #[test] + fn prepend_rows_empty_grid() { + let mut grid: Grid = Grid::init(0, 0, 0); + grid.prepend_rows(2); + + assert_eq!(grid.size(), (0, 0)); + assert_eq!(grid.order, Order::RowMajor); + assert_eq!(grid.rows(), 0); + assert_eq!(grid.cols(), 0); + assert_eq!(grid.into_vec(), Vec::::new()); + } + + #[test] + fn prepend_cols() { + let mut grid = Grid::from_vec_with_order(vec![1, 1, 1, 2, 2, 2], 3, Order::RowMajor); + grid.prepend_cols(2); + + assert_eq!(grid.size(), (2, 5)); + assert_eq!(grid.order, Order::RowMajor); + assert_eq!(grid.rows(), 2); + assert_eq!(grid.cols(), 5); + assert_eq!(grid.into_vec(), vec![0, 0, 1, 1, 1, 0, 0, 2, 2, 2]); + } + + #[test] + fn prepend_cols_column_major() { + let mut grid = Grid::from_vec_with_order(vec![1, 2, 1, 2, 1, 2], 3, Order::ColumnMajor); + grid.prepend_cols(2); + + assert_eq!(grid.size(), (2, 5)); + assert_eq!(grid.order, Order::ColumnMajor); + assert_eq!(grid.rows(), 2); + assert_eq!(grid.cols(), 5); + assert_eq!(grid.into_vec(), vec![0, 0, 0, 0, 1, 2, 1, 2, 1, 2]); + } + + #[test] + fn prepend_cols_zero() { + let mut grid = Grid::from_vec_with_order(vec![1, 2, 1, 2], 2, Order::RowMajor); + grid.prepend_cols(0); + + assert_eq!(grid.size(), (2, 2)); + assert_eq!(grid.order, Order::RowMajor); + assert_eq!(grid.rows(), 2); + assert_eq!(grid.cols(), 2); + assert_eq!(grid.into_vec(), vec![1, 2, 1, 2]); + } + + #[test] + fn prepend_cols_empty_grid() { + let mut grid: Grid = Grid::init(0, 0, 0); + grid.prepend_cols(2); + + assert_eq!(grid.size(), (0, 0)); + assert_eq!(grid.order, Order::RowMajor); + assert_eq!(grid.rows(), 0); + assert_eq!(grid.cols(), 0); + assert_eq!(grid.into_vec(), Vec::::new()); + } + #[test] fn iter_row() { let grid = Grid::from_vec_with_order(vec![1, 2, 3, 4, 5, 6], 3, Order::RowMajor);