Skip to content

Instantly share code, notes, and snippets.

@ratijas
Forked from rust-play/playground.rs
Created April 8, 2020 13:37
Show Gist options
  • Save ratijas/c0122a7ec276966513f8f6e92bd080d0 to your computer and use it in GitHub Desktop.
Save ratijas/c0122a7ec276966513f8f6e92bd080d0 to your computer and use it in GitHub Desktop.
Using Box<[T]> in Rust for multi-dimensional arrays
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);
}
@ratijas
Copy link
Author

ratijas commented Apr 8, 2020

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment