#[derive(Clone, Debug, PartialEq)]
pub struct NVec<T> {
dimensions: Vec<usize>,
multipliers: Vec<usize>,
data: Vec<T>,
}
impl<T: Clone> NVec<T> {
fn make_multipliers(dimensions: &[usize]) -> Vec<usize> {
let mut result = Vec::new();
for index in 0..dimensions.len() {
let mut multiplier = 1;
for dim in dimensions[index + 1..].iter() {
multiplier *= *dim;
}
result.push(multiplier);
}
result
}
pub fn build_ok<E>(
dimensions: Vec<usize>,
mut value_builder: impl FnMut(Vec<usize>) -> Result<T, E>,
) -> Result<NVec<T>, E> {
let mut data = Vec::new();
for index in crate::util::nd_index_iter(dimensions.clone()) {
data.push(value_builder(index)?);
}
Ok(Self::from_vec_and_dims(
data,
dimensions.iter().map(|index| *index as usize).collect(),
))
}
pub fn build(
dimensions: Vec<usize>,
mut value_builder: impl FnMut(Vec<usize>) -> T,
) -> NVec<T> {
let mut data = Vec::new();
for index in crate::util::nd_index_iter(dimensions.clone()) {
data.push(value_builder(index));
}
Self::from_vec_and_dims(
data,
dimensions.iter().map(|index| *index as usize).collect(),
)
}
pub fn new(dimensions: Vec<usize>, filler_value: T) -> NVec<T> {
assert!(dimensions.len() > 0);
let mut size = 1;
for dim in dimensions.iter() {
let dim = *dim;
assert!(dim > 0);
size *= dim;
}
let mut result = NVec {
multipliers: Self::make_multipliers(&dimensions),
dimensions,
data: Vec::with_capacity(size),
};
for _ in 0..size {
result.data.push(filler_value.clone());
}
result
}
pub fn from_vec(items: Vec<T>) -> NVec<T> {
NVec {
multipliers: vec![1],
dimensions: vec![items.len()],
data: items,
}
}
pub fn from_vec_and_dims(items: Vec<T>, dimensions: Vec<usize>) -> NVec<T> {
let mut size = 1;
for dim in dimensions.iter() {
size *= *dim;
}
assert!(items.len() == size);
NVec {
multipliers: Self::make_multipliers(&dimensions),
dimensions: dimensions,
data: items,
}
}
pub fn collect(sub_arrays: Vec<NVec<T>>) -> NVec<T> {
assert!(sub_arrays.len() > 0);
let mut dimensions = sub_arrays[0].dimensions.clone();
let mut multipliers = sub_arrays[0].multipliers.clone();
for sub_array in sub_arrays.iter() {
assert!(sub_array.dimensions == dimensions);
}
dimensions.insert(0, sub_arrays.len());
multipliers.insert(0, sub_arrays[0].data.len());
let mut data = Vec::new();
for mut sub_array in sub_arrays.into_iter() {
data.append(&mut sub_array.data);
}
NVec {
multipliers,
dimensions,
data,
}
}
pub fn map<F, U>(&self, mutator: F) -> NVec<U>
where
F: Fn(&T) -> U,
U: Clone,
{
let mut new_items = Vec::new();
for old_item in self.data.iter() {
new_items.push(mutator(old_item));
}
NVec::from_vec_and_dims(new_items, self.dimensions.clone())
}
fn convert_to_raw_index(&self, coordinate: &[usize]) -> usize {
let mut index = 0;
for (coord, multiplier) in coordinate.iter().zip(self.multipliers.iter()) {
index += coord * multiplier;
}
index
}
pub fn is_slice_inside(&self, coordinate: &[usize]) -> bool {
if coordinate.len() > self.dimensions.len() {
return false;
}
for (coord, max) in coordinate.iter().zip(self.dimensions.iter()) {
if coord >= max {
return false;
}
}
true
}
pub fn is_inside(&self, coordinate: &[usize]) -> bool {
if coordinate.len() != self.dimensions.len() {
return false;
}
for (coord, max) in coordinate.iter().zip(self.dimensions.iter()) {
if coord >= max {
return false;
}
}
true
}
pub fn set_item(&mut self, coordinate: &[usize], value: T) {
assert!(self.is_inside(coordinate));
let index = self.convert_to_raw_index(coordinate);
self.data[index] = value;
}
pub fn clone_slice(&self, coordinate: &[usize]) -> Self {
assert!(self.is_slice_inside(coordinate));
let slice_order = coordinate.len();
let new_dimensions = Vec::from(&self.dimensions[slice_order..]);
let new_multipliers = Vec::from(&self.multipliers[slice_order..]);
let start_index = self.convert_to_raw_index(coordinate);
let size = if new_dimensions.len() == 0 {
1
} else {
new_dimensions[0] * new_multipliers[0]
};
NVec {
dimensions: new_dimensions,
multipliers: new_multipliers,
data: (&self.data[start_index..start_index + size]).into(),
}
}
pub fn borrow_item(&self, coordinate: &[usize]) -> &T {
assert!(self.is_inside(coordinate));
&self.data[self.convert_to_raw_index(coordinate)]
}
pub fn borrow_item_mut(&mut self, coordinate: &[usize]) -> &mut T {
assert!(self.is_inside(coordinate));
let index = self.convert_to_raw_index(coordinate);
&mut self.data[index]
}
pub fn borrow_all_items(&self) -> &Vec<T> {
&self.data
}
pub fn borrow_dimensions(&self) -> &[usize] {
&self.dimensions
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn store_fetch_1d() {
let mut array = NVec::new(vec![8], 0 as usize);
for x in 0..8 {
array.set_item(&vec![x], x * 2);
}
for x in 0..8 {
assert!(*array.borrow_item(&vec![x]) == x * 2);
}
}
#[test]
fn store_fetch_2d() {
let mut array = NVec::new(vec![4, 3], 0 as usize);
for x in 0..4 {
for y in 0..3 {
array.set_item(&vec![x, y], x + y * 10);
}
}
for x in 0..4 {
for y in 0..3 {
assert!(*array.borrow_item(&vec![x, y]) == x + y * 10);
}
}
}
#[test]
fn collect_2d() {
let mut arrays = Vec::with_capacity(3);
for x in 0..3 {
let mut array = NVec::new(vec![6], 0 as usize);
for y in 0..6 {
array.set_item(&vec![y], x + y * 10);
}
arrays.push(array);
}
let collected_array = NVec::collect(arrays);
for x in 0..3 {
for y in 0..6 {
assert!(*collected_array.borrow_item(&vec![x, y]) == x + y * 10);
}
}
}
#[test]
fn slice_2d() {
let mut array = NVec::new(vec![4, 3], 0 as usize);
for x in 0..4 {
for y in 0..3 {
array.set_item(&vec![x, y], x + y * 10);
}
}
for x in 0..4 {
let slice = array.clone_slice(&vec![x]);
for y in 0..3 {
assert!(*slice.borrow_item(&vec![y]) == x + y * 10);
}
}
}
}