|
|
@@ -0,0 +1,187 @@ |
|
|
use std::{fmt, ops}; |
|
|
|
|
|
pub struct Array2D<T> { |
|
|
width: usize, |
|
|
height: usize, |
|
|
data: Box<[T]>, |
|
|
} |
|
|
|
|
|
impl<T> Array2D<T> { |
|
|
pub fn new(size: (usize, usize)) -> Self |
|
|
where T: Default |
|
|
{ |
|
|
let (width, height) = size; |
|
|
assert_ne!(width, 0); |
|
|
assert_ne!(height, 0); |
|
|
let size = width.checked_mul(height).expect("Array of this size would not fit into memory"); |
|
|
let mut vec = Vec::with_capacity(size); |
|
|
vec.extend(std::iter::repeat_with(T::default).take(size)); |
|
|
let data = vec.into_boxed_slice(); |
|
|
Array2D { |
|
|
width, |
|
|
height, |
|
|
data, |
|
|
} |
|
|
} |
|
|
|
|
|
pub fn width(&self) -> usize { self.width } |
|
|
|
|
|
pub fn height(&self) -> usize { self.height } |
|
|
|
|
|
pub fn len(&self) -> usize { |
|
|
// probably faster than multiplication |
|
|
self.data.len() |
|
|
} |
|
|
|
|
|
fn make_index(&self, xy: (usize, usize)) -> usize { |
|
|
let (x, y) = xy; |
|
|
assert!(x < self.width); |
|
|
assert!(y < self.height); |
|
|
y * self.width + x |
|
|
} |
|
|
|
|
|
pub fn column(&self, column_index: usize) -> Column<T> { |
|
|
assert!(column_index < self.width()); |
|
|
Column::new(self, column_index) |
|
|
} |
|
|
|
|
|
pub fn columns<'a>(&'a self) -> impl Iterator<Item=Column<'a, T>> + 'a { |
|
|
(0..self.width()).map(move |x| self.column(x)) |
|
|
} |
|
|
|
|
|
pub fn row(&self, row_index: usize) -> Row<T> { |
|
|
assert!(row_index < self.height()); |
|
|
Row::new(self, row_index) |
|
|
} |
|
|
|
|
|
pub fn rows<'a>(&'a self) -> impl Iterator<Item=Row<'a, T>> + 'a { |
|
|
(0..self.height()).map(move |y| self.row(y)) |
|
|
} |
|
|
} |
|
|
|
|
|
impl<T> ops::Index<(usize, usize)> for Array2D<T> { |
|
|
type Output = T; |
|
|
|
|
|
fn index(&self, xy: (usize, usize)) -> &T { |
|
|
let index = self.make_index(xy); |
|
|
&self.data[index] |
|
|
} |
|
|
} |
|
|
|
|
|
impl<T> ops::IndexMut<(usize, usize)> for Array2D<T> { |
|
|
fn index_mut(&mut self, xy: (usize, usize)) -> &mut T { |
|
|
let index = self.make_index(xy); |
|
|
&mut self.data[index] |
|
|
} |
|
|
} |
|
|
|
|
|
impl<T> fmt::Display for Array2D<T> |
|
|
where T: fmt::Display |
|
|
{ |
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
|
|
"Array2D([\n".fmt(f)?; |
|
|
for row in self.rows() { |
|
|
" [".fmt(f)?; |
|
|
for (x, item) in row.enumerate() { |
|
|
write!(f, "{}", item)?; |
|
|
if x != (self.width() - 1) { |
|
|
", ".fmt(f)?; |
|
|
} |
|
|
} |
|
|
"]\n".fmt(f)?; |
|
|
} |
|
|
"])".fmt(f)?; |
|
|
Ok(()) |
|
|
} |
|
|
} |
|
|
|
|
|
pub struct Row<'a, T> { |
|
|
array: &'a Array2D<T>, |
|
|
row: usize, |
|
|
current_column: usize, |
|
|
} |
|
|
|
|
|
impl<'a, T> Row<'a, T> { |
|
|
pub fn new(array: &'a Array2D<T>, row: usize) -> Self { |
|
|
assert!(row < array.height); |
|
|
|
|
|
Row { |
|
|
array, |
|
|
row, |
|
|
current_column: 0 |
|
|
} |
|
|
} |
|
|
|
|
|
pub fn current_column(&self) -> usize { |
|
|
self.current_column |
|
|
} |
|
|
} |
|
|
|
|
|
impl<'a, T> Iterator for Row<'a, T> { |
|
|
type Item = &'a T; |
|
|
|
|
|
fn next(&mut self) -> Option<&'a T> { |
|
|
if self.current_column >= self.array.width() { |
|
|
None |
|
|
} else { |
|
|
let index = (self.current_column, self.row); |
|
|
let item = &self.array[index]; |
|
|
self.current_column += 1; |
|
|
Some(item) |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
pub struct Column<'a, T> { |
|
|
array: &'a Array2D<T>, |
|
|
column: usize, |
|
|
current_row: usize, |
|
|
} |
|
|
|
|
|
impl<'a, T> Column<'a, T> { |
|
|
pub fn new(array: &'a Array2D<T>, column: usize) -> Self { |
|
|
assert!(column < array.width); |
|
|
|
|
|
Column { |
|
|
array, |
|
|
column, |
|
|
current_row: 0 |
|
|
} |
|
|
} |
|
|
|
|
|
pub fn current_row(&self) -> usize { |
|
|
self.current_row |
|
|
} |
|
|
} |
|
|
|
|
|
impl<'a, T> Iterator for Column<'a, T> { |
|
|
type Item = &'a T; |
|
|
|
|
|
fn next(&mut self) -> Option<&'a T> { |
|
|
if self.current_row >= self.array.height() { |
|
|
None |
|
|
} else { |
|
|
let index = (self.column, self.current_row); |
|
|
let item = &self.array[index]; |
|
|
self.current_row += 1; |
|
|
Some(item) |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
fn incremental_array(size: (usize, usize)) -> Array2D<u8> { |
|
|
let mut array = Array2D::new(size); |
|
|
let mut item = 0u8; |
|
|
for x in 0..array.width() { |
|
|
for y in 0..array.height() { |
|
|
array[(x, y)] = item; |
|
|
item += 1; |
|
|
} |
|
|
} |
|
|
array |
|
|
} |
|
|
|
|
|
fn main() { |
|
|
let a = incremental_array((10, 15)); |
|
|
println!("{}", a); |
|
|
} |