use std::ops::{Index, IndexMut};
#[derive(Debug)]
pub struct Vec2D<T> {
data: Box<[T]>,
cols: usize,
}
impl<T> Vec2D<T> {
pub fn init(data: T, size: (usize, usize)) -> Vec2D<T>
where
T: Clone,
{
let (rows, cols) = size;
let len = rows
.checked_mul(cols)
.unwrap_or_else(|| panic!("{} rows by {} cols exceeds usize::MAX", rows, cols));
Vec2D {
data: vec![data; len].into_boxed_slice(),
cols,
}
}
pub fn fill(&mut self, value: T)
where
T: Clone,
{
self.data.fill(value)
}
}
impl<T> Index<usize> for Vec2D<T> {
type Output = [T];
#[inline]
fn index(&self, row: usize) -> &Self::Output {
let start_row = row
.checked_mul(self.cols)
.unwrap_or_else(|| panic!("{} row by {} cols exceeds usize::MAX", row, self.cols));
&self.data[start_row..start_row + self.cols]
}
}
impl<T> IndexMut<usize> for Vec2D<T> {
#[inline]
fn index_mut(&mut self, row: usize) -> &mut Self::Output {
let start_row = row
.checked_mul(self.cols)
.unwrap_or_else(|| panic!("{} row by {} cols exceeds usize::MAX", row, self.cols));
&mut self.data[start_row..start_row + self.cols]
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn init() {
let vec2d = Vec2D::init(1, (2, 3));
assert_eq!(vec2d[0], [1, 1, 1]);
assert_eq!(vec2d[1], [1, 1, 1]);
}
#[test]
#[should_panic]
fn init_overflow() {
Vec2D::init(1, (usize::MAX, usize::MAX));
}
#[test]
fn fill() {
let mut vec2d = Vec2D::init(0, (2, 3));
vec2d.fill(7);
assert_eq!(vec2d[0], [7, 7, 7]);
assert_eq!(vec2d[1], [7, 7, 7]);
}
#[test]
fn index() {
let vec2d = Vec2D {
data: vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice(),
cols: 2,
};
assert_eq!(vec2d[0], [0, 1]);
assert_eq!(vec2d[1], [2, 3]);
assert_eq!(vec2d[2], [4, 5]);
assert_eq!(vec2d[3], [6, 7]);
}
#[test]
fn indexmut() {
let mut vec2d = Vec2D {
data: vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice(),
cols: 2,
};
vec2d[1][1] = 9;
assert_eq!(vec2d[0], [0, 1]);
assert_eq!(vec2d[1], [2, 9]);
assert_eq!(vec2d[2], [4, 5]);
assert_eq!(vec2d[3], [6, 7]);
}
#[test]
#[should_panic]
fn index_out_of_bounds() {
let vec2d = Vec2D::init(1, (2, 3));
let _x = vec2d[2][3];
}
#[test]
#[should_panic]
fn index_out_of_bounds_vec_edge() {
let vec2d = Vec2D::init(1, (2, 3));
let _x = vec2d[1][3];
}
#[test]
#[should_panic]
fn index_column_out_of_bounds() {
let vec2d = Vec2D::init(1, (2, 3));
let _x = vec2d[0][3];
}
#[test]
#[should_panic]
fn index_row_out_of_bounds() {
let vec2d = Vec2D::init(1, (2, 3));
let _x = vec2d[2][0];
}
#[test]
#[should_panic]
fn index_mul_overflow() {
let matrix = Vec2D::init(0, (3, 4));
let row = (usize::MAX / 4) + 1;
let _ = matrix[row];
}
#[test]
#[should_panic]
fn index_add_overflow() {
let matrix = Vec2D::init(0, (3, 5));
let row = usize::MAX / 5;
let _ = matrix[row];
}
#[test]
#[should_panic]
fn indexmut_out_of_bounds() {
let mut vec2d = Vec2D::init(1, (2, 3));
vec2d[2][3] = 0;
}
#[test]
#[should_panic]
fn indexmut_out_of_bounds_vec_edge() {
let mut vec2d = Vec2D::init(1, (2, 3));
vec2d[1][3] = 0;
}
#[test]
#[should_panic]
fn indexmut_column_out_of_bounds() {
let mut vec2d = Vec2D::init(1, (2, 3));
vec2d[0][3] = 0;
}
#[test]
#[should_panic]
fn indexmut_row_out_of_bounds() {
let mut vec2d = Vec2D::init(1, (2, 3));
vec2d[2][0] = 0;
}
#[test]
#[should_panic]
fn indexmut_mul_overflow() {
let mut matrix = Vec2D::init(0, (3, 4));
let row = (usize::MAX / 4) + 1;
matrix[row][0] = 9;
}
#[test]
#[should_panic]
fn indexmut_add_overflow() {
let mut matrix = Vec2D::init(0, (3, 5));
let row = usize::MAX / 5;
matrix[row][0] = 9;
}
}