commit
4732783d4a
4 changed files with 327 additions and 97 deletions
|
@ -4,10 +4,9 @@ version = "0.1.0"
|
|||
authors = ["Armin Becher <armin.becher@gmai.com>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = "0.3.1"
|
||||
rand="0.7.3"
|
||||
|
||||
[[bench]]
|
||||
name = "benches"
|
||||
|
|
|
@ -1,85 +1,113 @@
|
|||
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
||||
use criterion::{criterion_group, criterion_main, Criterion};
|
||||
use grid::grid;
|
||||
use grid::Grid;
|
||||
use rand::Rng;
|
||||
|
||||
fn init_vec_vec(size: usize) -> Vec<Vec<u32>> {
|
||||
vec![vec![0; size]; size]
|
||||
const SIZE: usize = 1000;
|
||||
|
||||
fn init_vec_vec() -> Vec<Vec<u32>> {
|
||||
vec![vec![0; SIZE]; SIZE]
|
||||
}
|
||||
|
||||
fn init_vec_flat(size: usize) -> Vec<u32> {
|
||||
vec![0; size * size]
|
||||
fn init_vec_flat() -> Vec<u32> {
|
||||
vec![0; SIZE * SIZE]
|
||||
}
|
||||
|
||||
fn init_grid(size: usize) -> Grid<u32> {
|
||||
Grid::new(size, size, 0)
|
||||
}
|
||||
|
||||
fn get_vec_vec(x: usize, y: usize) -> u32 {
|
||||
let mat = init_vec_vec(10);
|
||||
mat[x][y]
|
||||
}
|
||||
|
||||
fn get_vec_flat(x: usize, y: usize) -> u32 {
|
||||
let mat = init_vec_flat(10);
|
||||
mat[x * 10 + y % 10]
|
||||
}
|
||||
|
||||
fn get_grid(x: usize, y: usize) -> u32 {
|
||||
let mat = init_grid(10);
|
||||
mat[x][y]
|
||||
}
|
||||
|
||||
fn get_grid_fn(x: usize, y: usize) {
|
||||
let mat = init_grid(10);
|
||||
mat.get(x, y);
|
||||
}
|
||||
|
||||
fn set_vec_vec(x: usize, y: usize) {
|
||||
let mut mat = init_vec_vec(10);
|
||||
mat[x][y] = 10;
|
||||
}
|
||||
fn set_vec_flat(x: usize, y: usize) {
|
||||
let mut mat = init_vec_flat(10);
|
||||
mat[x * 10 + y % 10] = 10;
|
||||
}
|
||||
|
||||
fn set_grid(x: usize, y: usize) {
|
||||
let mut mat = init_grid(10);
|
||||
mat[x][y] = 10;
|
||||
fn init_grid() -> Grid<u32> {
|
||||
Grid::init(SIZE, SIZE, 0)
|
||||
}
|
||||
|
||||
fn criterion_benchmark(c: &mut Criterion) {
|
||||
// Init
|
||||
c.bench_function("Init vec vec 10x10", |b| {
|
||||
b.iter(|| init_vec_vec(black_box(10)))
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut rand = || rng.gen_range(0, SIZE);
|
||||
|
||||
let mut rng_u32 = rand::thread_rng();
|
||||
let mut rand_u32 = || rng_u32.gen::<u32>();
|
||||
|
||||
// Init macro
|
||||
c.bench_function("Macro init vec vec", |b| {
|
||||
b.iter(|| {
|
||||
vec![
|
||||
vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
|
||||
vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
|
||||
vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
|
||||
vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
|
||||
vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
|
||||
vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
|
||||
vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
|
||||
vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
|
||||
vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
|
||||
vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
|
||||
]
|
||||
})
|
||||
});
|
||||
c.bench_function("Init vec flat 10x10", |b| {
|
||||
b.iter(|| init_vec_flat(black_box(10)))
|
||||
c.bench_function("Macro init vec flat", |b| {
|
||||
b.iter(|| {
|
||||
vec![
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7,
|
||||
8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5,
|
||||
6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3,
|
||||
4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
|
||||
]
|
||||
})
|
||||
});
|
||||
c.bench_function("Init grid 10x10", |b| b.iter(|| init_grid(black_box(10))));
|
||||
c.bench_function("Macro init grid from_vec", |b| {
|
||||
b.iter(|| {
|
||||
let vec = vec![
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7,
|
||||
8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5,
|
||||
6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3,
|
||||
4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
|
||||
];
|
||||
Grid::from_vec(vec, 10)
|
||||
})
|
||||
});
|
||||
c.bench_function("Macro init grid", |b| {
|
||||
b.iter(|| {
|
||||
grid![[0,1,2,3,4,5,6,7,8,9]
|
||||
[0,1,2,3,4,5,6,7,8,9]
|
||||
[0,1,2,3,4,5,6,7,8,9]
|
||||
[0,1,2,3,4,5,6,7,8,9]
|
||||
[0,1,2,3,4,5,6,7,8,9]
|
||||
[0,1,2,3,4,5,6,7,8,9]
|
||||
[0,1,2,3,4,5,6,7,8,9]
|
||||
[0,1,2,3,4,5,6,7,8,9]
|
||||
[0,1,2,3,4,5,6,7,8,9]
|
||||
[0,1,2,3,4,5,6,7,8,9]]
|
||||
})
|
||||
});
|
||||
|
||||
// New
|
||||
c.bench_function("Init vec vec", |b| b.iter(|| init_vec_vec()));
|
||||
c.bench_function("Init vec flat", |b| b.iter(|| init_vec_flat()));
|
||||
c.bench_function("Init grid", |b| b.iter(|| init_grid()));
|
||||
|
||||
// Get
|
||||
c.bench_function("Get vec vec 10x10", |b| {
|
||||
b.iter(|| get_vec_vec(black_box(2), black_box(3)))
|
||||
c.bench_function("Idx vec vec", |b| {
|
||||
let vec_vec = init_vec_vec();
|
||||
b.iter(|| vec_vec[rand()][rand()])
|
||||
});
|
||||
c.bench_function("Get vec flat 10x10", |b| {
|
||||
b.iter(|| get_vec_flat(black_box(2), black_box(3)))
|
||||
c.bench_function("Idx grid", |b| {
|
||||
let grid = init_grid();
|
||||
b.iter(|| grid[rand()][rand()])
|
||||
});
|
||||
c.bench_function("Get grid 10x10", |b| {
|
||||
b.iter(|| get_grid(black_box(2), black_box(3)))
|
||||
c.bench_function("Get_fn vec vec", |b| {
|
||||
let vec_vec = init_vec_vec();
|
||||
b.iter(|| vec_vec.get(rand()).unwrap().get(rand()))
|
||||
});
|
||||
c.bench_function("Get grid fn 10x10", |b| {
|
||||
b.iter(|| get_grid_fn(black_box(2), black_box(3)))
|
||||
c.bench_function("Get_fn grid", |b| {
|
||||
let grid = init_grid();
|
||||
b.iter(|| grid.get(rand(), rand()))
|
||||
});
|
||||
|
||||
//Set
|
||||
c.bench_function("Set vec vec 10x10", |b| {
|
||||
b.iter(|| set_vec_vec(black_box(2), black_box(3)))
|
||||
c.bench_function("Set vec vec", |b| {
|
||||
let mut vec_vec = init_vec_vec();
|
||||
b.iter(|| vec_vec[rand()][rand()] = rand_u32())
|
||||
});
|
||||
c.bench_function("Set vec flat 10x10", |b| {
|
||||
b.iter(|| set_vec_flat(black_box(2), black_box(3)))
|
||||
});
|
||||
c.bench_function("Set grid 10x10", |b| {
|
||||
b.iter(|| set_grid(black_box(2), black_box(3)))
|
||||
c.bench_function("Set gird", |b| {
|
||||
let mut gird = init_grid();
|
||||
b.iter(|| gird[rand()][rand()] = rand_u32())
|
||||
});
|
||||
}
|
||||
|
||||
|
|
267
src/lib.rs
267
src/lib.rs
|
@ -1,30 +1,164 @@
|
|||
use std::ops::Index;
|
||||
use std::ops::IndexMut;
|
||||
|
||||
/// Stores elements of a certain type in a 2D grid structure.
|
||||
pub struct Grid<T> {
|
||||
data: Vec<T>,
|
||||
columns: usize,
|
||||
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 {
|
||||
() => {
|
||||
Grid {
|
||||
rows: 0,
|
||||
cols: 0,
|
||||
data: vec![],
|
||||
}
|
||||
};
|
||||
( [$( $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<T: Clone> Grid<T> {
|
||||
pub fn new(rows: usize, columns: usize, data: T) -> Grid<T> {
|
||||
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<u8> = Grid::new(2,2);
|
||||
/// assert_eq!(grid[0][0], 0);
|
||||
/// ```
|
||||
pub fn new(rows: usize, cols: usize) -> Grid<T>
|
||||
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<T> {
|
||||
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<T>, cols: usize) -> Grid<T> {
|
||||
if vec.len() == 0 {
|
||||
if cols == 0 {
|
||||
return grid![];
|
||||
} else {
|
||||
panic!("Vector length is zero, but cols is {:?}", cols);
|
||||
}
|
||||
}
|
||||
if vec.len() % cols != 0 {
|
||||
panic!("Vector length must be a multiple of cols.");
|
||||
}
|
||||
let rows = vec.len();
|
||||
Grid {
|
||||
data: vec,
|
||||
rows: rows / cols,
|
||||
cols: cols,
|
||||
}
|
||||
}
|
||||
|
||||
/// 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.data.get_unchecked(row * self.cols() + col)) }
|
||||
//Some(&self.data.get_unchecked(row * self.cols() + 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.columns)
|
||||
(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
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -32,25 +166,20 @@ impl<T: Clone> Index<usize> for Grid<T> {
|
|||
type Output = [T];
|
||||
|
||||
fn index(&self, idx: usize) -> &Self::Output {
|
||||
if idx >= self.rows {
|
||||
if idx < self.rows {
|
||||
&self.data[(idx * &self.cols)..]
|
||||
} else {
|
||||
panic!(
|
||||
"index out of bounds: grid has {:?} but the index is {:?}",
|
||||
"index {:?} out of bounds. Grid has {:?} rows.",
|
||||
self.rows, idx
|
||||
);
|
||||
}
|
||||
&self.data[(idx * &self.columns)..]
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Clone> IndexMut<usize> for Grid<T> {
|
||||
fn index_mut(&mut self, idx: usize) -> &mut Self::Output {
|
||||
if idx >= self.rows {
|
||||
panic!(
|
||||
"index out of bounds: grid has {:?} but the index is {:?}",
|
||||
self.rows, idx
|
||||
);
|
||||
}
|
||||
&mut self.data[(idx * &self.columns)..]
|
||||
&mut self.data[(idx * &self.cols)..]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -59,64 +188,138 @@ 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() {
|
||||
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<usize> = 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<usize> = grid![];
|
||||
assert_eq!(grid.size(), (0, 0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_vec_zero() {
|
||||
let grid: Grid<u8> = Grid::from_vec(vec![], 0);
|
||||
assert_eq!(grid.size(), (0, 0));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn ctr_panics() {
|
||||
Grid::new(0, 2, 3);
|
||||
fn from_vec_panics_1() {
|
||||
let _: Grid<u8> = Grid::from_vec(vec![1, 2, 3], 0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn from_vec_panics_2() {
|
||||
let _: Grid<u8> = Grid::from_vec(vec![1, 2, 3], 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn from_vec_panics_3() {
|
||||
let _: Grid<u8> = 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<u8> = 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::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));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue