Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions benches/benches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
190 changes: 190 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1698,6 +1698,100 @@ impl<T: Default> Grid<T> {
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<u8> = 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<u8> = 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<T> Default for Grid<T> {
Expand Down Expand Up @@ -2757,6 +2851,102 @@ mod test {
assert_eq!(grid.into_vec(), Vec::<u8>::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<u8> = 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::<u8>::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<u8> = 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::<u8>::new());
}

#[test]
fn iter_row() {
let grid = Grid::from_vec_with_order(vec![1, 2, 3, 4, 5, 6], 3, Order::RowMajor);
Expand Down
Loading