use crate::{
access::{GetUnchecked, GetUncheckedMut, GetUncheckedMutRelease, GetUncheckedRelease},
chunk_map::ChunkCopySrc,
ForEach, ForEachMut, Get, GetMut, ReadExtent, TransformMap, WriteExtent,
};
use building_blocks_core::prelude::*;
use compressible_map::{Compressible, Decompressible};
use core::iter::{once, Once};
use core::mem::MaybeUninit;
use core::ops::{Add, AddAssign, Deref, Mul, Sub, SubAssign};
use either::Either;
use num::Zero;
use serde::{Deserialize, Serialize};
pub trait Array<N> {
type Indexer: ArrayIndexer<N>;
fn extent(&self) -> &ExtentN<N>;
fn for_each_point_and_stride(&self, extent: &ExtentN<N>, f: impl FnMut(PointN<N>, Stride)) {
Self::Indexer::for_each_point_and_stride(self.extent(), extent, f);
}
fn stride_from_local_point(&self, p: &Local<N>) -> Stride {
Self::Indexer::stride_from_local_point(&self.extent().shape, p)
}
fn strides_from_local_points(&self, points: &[Local<N>], strides: &mut [Stride]) {
for (i, p) in points.iter().enumerate() {
strides[i] = self.stride_from_local_point(p);
}
}
}
impl<N, T> Array<N> for ArrayN<N, T>
where
N: ArrayIndexer<N>,
{
type Indexer = N;
fn extent(&self) -> &ExtentN<N> {
self.extent()
}
}
pub trait ArrayIndexer<N> {
fn stride_from_local_point(shape: &PointN<N>, point: &Local<N>) -> Stride;
fn for_each_point_and_stride(
array_extent: &ExtentN<N>,
extent: &ExtentN<N>,
f: impl FnMut(PointN<N>, Stride),
);
fn for_each_stride_parallel(
iter_extent: &ExtentN<N>,
array1_extent: &ExtentN<N>,
array2_extent: &ExtentN<N>,
f: impl FnMut(Stride, Stride),
);
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct ArrayN<N, T> {
values: Vec<T>,
extent: ExtentN<N>,
}
impl<N, T> ArrayN<N, T> {
pub fn reset_values(&mut self, value: T)
where
T: Clone,
{
for v in self.values.iter_mut() {
*v = value.clone();
}
}
pub fn values_slice(&self) -> &[T] {
&self.values[..]
}
pub fn into_parts(self) -> (ExtentN<N>, Vec<T>) {
(self.extent, self.values)
}
pub fn extent(&self) -> &ExtentN<N> {
&self.extent
}
}
impl<N, T> ArrayN<N, T>
where
ExtentN<N>: IntegerExtent<N>,
{
pub fn new(extent: ExtentN<N>, values: Vec<T>) -> Self {
assert_eq!(extent.num_points(), values.len());
Self { values, extent }
}
pub unsafe fn maybe_uninit(extent: ExtentN<N>) -> ArrayN<N, MaybeUninit<T>> {
let num_points = extent.num_points();
let mut values = Vec::with_capacity(num_points);
values.set_len(num_points);
ArrayN::new(extent, values)
}
pub fn fill(extent: ExtentN<N>, value: T) -> Self
where
T: Clone,
{
Self::new(extent, vec![value; extent.num_points()])
}
pub fn set_minimum(&mut self, p: PointN<N>) {
self.extent.minimum = p;
}
}
impl<N, T> ArrayN<N, T>
where
PointN<N>: Point,
{
pub fn contains(&self, p: &PointN<N>) -> bool {
self.extent.contains(p)
}
}
impl<N, T> ArrayN<N, T>
where
PointN<N>: Point,
ExtentN<N>: IntegerExtent<N>,
{
pub fn fill_with(extent: ExtentN<N>, mut filler: impl FnMut(&PointN<N>) -> T) -> Self
where
ArrayN<N, MaybeUninit<T>>: for<'r> GetMut<&'r PointN<N>, Data = MaybeUninit<T>>,
{
let mut array = unsafe { Self::maybe_uninit(extent) };
for p in extent.iter_points() {
unsafe {
array.get_mut(&p).as_mut_ptr().write(filler(&p));
}
}
unsafe { array.assume_init() }
}
pub fn translate(&mut self, p: PointN<N>) {
self.extent = self.extent.add(p);
}
}
impl<N, T> ArrayN<N, T>
where
Self: ForEachMut<N, Stride, Data = T>,
{
pub fn fill_extent(&mut self, extent: &ExtentN<N>, value: T)
where
T: Clone,
{
self.for_each_mut(extent, |_s: Stride, v| *v = value.clone());
}
}
impl<N, T> ArrayN<N, MaybeUninit<T>>
where
PointN<N>: Point,
ExtentN<N>: IntegerExtent<N>,
{
pub unsafe fn assume_init(self) -> ArrayN<N, T> {
let transmuted_values = {
let mut v_clone = core::mem::ManuallyDrop::new(self.values);
Vec::from_raw_parts(
v_clone.as_mut_ptr() as *mut T,
v_clone.len(),
v_clone.capacity(),
)
};
ArrayN::new(self.extent, transmuted_values)
}
}
pub struct Local<N>(pub PointN<N>);
impl<N> Local<N> {
pub fn localize_points(points: &[PointN<N>]) -> Vec<Local<N>>
where
PointN<N>: Clone,
{
points.iter().cloned().map(Local).collect()
}
}
impl<N> Deref for Local<N> {
type Target = PointN<N>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Stride(pub usize);
impl Zero for Stride {
fn zero() -> Self {
Stride(0)
}
fn is_zero(&self) -> bool {
self.0 == 0
}
}
impl Add for Stride {
type Output = Self;
fn add(self, rhs: Self) -> Self::Output {
Self(self.0.wrapping_add(rhs.0))
}
}
impl Sub for Stride {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output {
Self(self.0.wrapping_sub(rhs.0))
}
}
impl Mul<usize> for Stride {
type Output = Self;
fn mul(self, rhs: usize) -> Self::Output {
Self(self.0.wrapping_mul(rhs))
}
}
impl AddAssign for Stride {
fn add_assign(&mut self, rhs: Self) {
*self = *self + rhs;
}
}
impl SubAssign for Stride {
fn sub_assign(&mut self, rhs: Self) {
*self = *self - rhs;
}
}
impl<N, T> Get<Stride> for ArrayN<N, T>
where
T: Clone,
{
type Data = T;
#[inline]
fn get(&self, stride: Stride) -> Self::Data {
self.values[stride.0].clone()
}
}
impl<N, T> GetUnchecked<Stride> for ArrayN<N, T>
where
T: Clone,
{
type Data = T;
#[inline]
unsafe fn get_unchecked(&self, stride: Stride) -> Self::Data {
self.values.get_unchecked(stride.0).clone()
}
}
impl<N, T> GetMut<Stride> for ArrayN<N, T> {
type Data = T;
fn get_mut(&mut self, stride: Stride) -> &mut Self::Data {
&mut self.values[stride.0]
}
}
impl<N, T> GetUncheckedMut<Stride> for ArrayN<N, T> {
type Data = T;
unsafe fn get_unchecked_mut(&mut self, stride: Stride) -> &mut Self::Data {
self.values.get_unchecked_mut(stride.0)
}
}
impl<N, T> Get<&Local<N>> for ArrayN<N, T>
where
T: Clone,
Self: Array<N> + Get<Stride, Data = T>,
{
type Data = T;
#[inline]
fn get(&self, p: &Local<N>) -> Self::Data {
self.get(self.stride_from_local_point(p))
}
}
impl<N, T> GetMut<&Local<N>> for ArrayN<N, T>
where
Self: Array<N> + GetMut<Stride, Data = T>,
{
type Data = T;
#[inline]
fn get_mut(&mut self, p: &Local<N>) -> &mut Self::Data {
self.get_mut(self.stride_from_local_point(p))
}
}
impl<N, T> Get<&PointN<N>> for ArrayN<N, T>
where
T: Clone,
Self: Array<N> + for<'r> Get<&'r Local<N>, Data = T>,
PointN<N>: Point,
{
type Data = T;
#[inline]
fn get(&self, p: &PointN<N>) -> Self::Data {
let local_p = *p - self.extent().minimum;
self.get(&Local(local_p))
}
}
impl<N, T> GetMut<&PointN<N>> for ArrayN<N, T>
where
Self: Array<N> + for<'r> GetMut<&'r Local<N>, Data = T>,
PointN<N>: Point,
{
type Data = T;
#[inline]
fn get_mut(&mut self, p: &PointN<N>) -> &mut Self::Data {
let local_p = *p - self.extent().minimum;
GetMut::<&Local<N>>::get_mut(self, &Local(local_p))
}
}
impl<N, T> GetUnchecked<&Local<N>> for ArrayN<N, T>
where
T: Clone,
Self: Array<N> + GetUnchecked<Stride, Data = T>,
{
type Data = T;
#[inline]
unsafe fn get_unchecked(&self, p: &Local<N>) -> Self::Data {
self.get_unchecked(self.stride_from_local_point(p))
}
}
impl<N, T> GetUncheckedMut<&Local<N>> for ArrayN<N, T>
where
Self: Array<N> + GetUncheckedMut<Stride, Data = T>,
{
type Data = T;
#[inline]
unsafe fn get_unchecked_mut(&mut self, p: &Local<N>) -> &mut Self::Data {
self.get_unchecked_mut(self.stride_from_local_point(p))
}
}
impl<N, T> GetUnchecked<&PointN<N>> for ArrayN<N, T>
where
T: Clone,
Self: Array<N> + for<'r> GetUnchecked<&'r Local<N>, Data = T>,
PointN<N>: Point,
{
type Data = T;
#[inline]
unsafe fn get_unchecked(&self, p: &PointN<N>) -> Self::Data {
let local_p = *p - self.extent().minimum;
self.get_unchecked(&Local(local_p))
}
}
impl<N, T> GetUncheckedMut<&PointN<N>> for ArrayN<N, T>
where
Self: Array<N> + for<'r> GetUncheckedMut<&'r Local<N>, Data = T>,
PointN<N>: Point,
{
type Data = T;
#[inline]
unsafe fn get_unchecked_mut(&mut self, p: &PointN<N>) -> &mut Self::Data {
let local_p = *p - self.extent().minimum;
GetUncheckedMut::<&Local<N>>::get_unchecked_mut(self, &Local(local_p))
}
}
macro_rules! impl_array_for_each {
(coords: $coords:ty; forwarder = |$p:ident, $stride:ident| $forward_coords:expr;) => {
impl<N, T> ForEach<N, $coords> for ArrayN<N, T>
where
Self: Sized + Array<N> + Get<Stride, Data = T> + GetUnchecked<Stride, Data = T>,
{
type Data = T;
fn for_each(&self, extent: &ExtentN<N>, mut f: impl FnMut($coords, T)) {
<Self as Array<N>>::Indexer::for_each_point_and_stride(
self.extent(),
&extent,
|$p, $stride| f($forward_coords, self.get_unchecked_release($stride)),
)
}
}
impl<N, T> ForEachMut<N, $coords> for ArrayN<N, T>
where
Self: Sized + Array<N> + GetMut<Stride, Data = T> + GetUncheckedMut<Stride, Data = T>,
ExtentN<N>: Copy,
{
type Data = T;
fn for_each_mut(&mut self, extent: &ExtentN<N>, mut f: impl FnMut($coords, &mut T)) {
let array_extent = *self.extent();
<Self as Array<N>>::Indexer::for_each_point_and_stride(
&array_extent,
&extent,
|$p, $stride| f($forward_coords, self.get_unchecked_mut_release($stride)),
)
}
}
};
}
impl_array_for_each!(
coords: (PointN<N>, Stride);
forwarder = |p, stride| (p, stride);
);
impl_array_for_each!(
coords: Stride;
forwarder = |_p, stride| stride;
);
impl_array_for_each!(
coords: PointN<N>;
forwarder = |p, stride| p;
);
#[derive(Copy, Clone)]
pub struct ArrayCopySrc<M>(pub M);
impl<'a, N: 'a, T: 'a> ReadExtent<'a, N> for ArrayN<N, T>
where
PointN<N>: IntegerPoint,
{
type Src = ArrayCopySrc<&'a ArrayN<N, T>>;
type SrcIter = Once<(ExtentN<N>, Self::Src)>;
fn read_extent(&'a self, extent: &ExtentN<N>) -> Self::SrcIter {
let in_bounds_extent = extent.intersection(self.extent());
once((in_bounds_extent, ArrayCopySrc(&self)))
}
}
impl<'a, N, T> WriteExtent<N, ArrayCopySrc<&'a Self>> for ArrayN<N, T>
where
Self: Array<N> + GetUncheckedRelease<Stride, T>,
T: Clone,
PointN<N>: IntegerPoint,
ExtentN<N>: Copy,
{
fn write_extent(&mut self, extent: &ExtentN<N>, src_array: ArrayCopySrc<&'a Self>) {
let in_bounds_extent = extent.intersection(self.extent());
let copy_entire_array = in_bounds_extent.shape == self.extent().shape
&& in_bounds_extent.shape == src_array.0.extent().shape;
if copy_entire_array {
self.values = src_array.0.values.clone();
} else {
unchecked_copy_extent_between_arrays(self, src_array.0, &in_bounds_extent);
}
}
}
impl<'a, N, T, M, F> WriteExtent<N, ArrayCopySrc<TransformMap<'a, M, F>>> for ArrayN<N, T>
where
Self: Array<N>,
T: Clone,
TransformMap<'a, M, F>: Array<N> + GetUncheckedRelease<Stride, T>,
PointN<N>: IntegerPoint,
ExtentN<N>: Copy,
{
fn write_extent(
&mut self,
extent: &ExtentN<N>,
src_array: ArrayCopySrc<TransformMap<'a, M, F>>,
) {
let in_bounds_extent = extent.intersection(self.extent());
unchecked_copy_extent_between_arrays(self, &src_array.0, &in_bounds_extent);
}
}
fn unchecked_copy_extent_between_arrays<Dst, Src, N, T>(
dst: &mut Dst,
src: &Src,
extent: &ExtentN<N>,
) where
Dst: Array<N> + GetUncheckedMutRelease<Stride, T>,
Src: Array<N> + GetUncheckedRelease<Stride, T>,
ExtentN<N>: Copy,
{
let dst_extent = *dst.extent();
Dst::Indexer::for_each_stride_parallel(&extent, &dst_extent, src.extent(), |s_dst, s_src| {
*dst.get_unchecked_mut_release(s_dst) = src.get_unchecked_release(s_src);
});
}
impl<M, N, T> WriteExtent<N, ChunkCopySrc<M, N, T>> for ArrayN<N, T>
where
T: Clone,
Self: Array<N> + WriteExtent<N, ArrayCopySrc<M>>,
ExtentN<N>: Copy,
{
fn write_extent(&mut self, extent: &ExtentN<N>, src: ChunkCopySrc<M, N, T>) {
match src {
Either::Left(array) => self.write_extent(extent, array),
Either::Right(ambient) => self.fill_extent(extent, ambient.get()),
}
}
}
impl<'a, N, F, T: 'a + Clone> WriteExtent<N, F> for ArrayN<N, T>
where
F: Fn(&PointN<N>) -> T,
PointN<N>: IntegerPoint,
ExtentN<N>: IntegerExtent<N>,
ArrayN<N, T>: ForEachMut<N, PointN<N>, Data = T>,
{
fn write_extent(&mut self, extent: &ExtentN<N>, src: F) {
self.for_each_mut(extent, |p, v| *v = (src)(&p));
}
}
#[derive(Clone, Copy, Debug)]
pub struct FastLz4 {
pub level: u32,
}
#[derive(Clone)]
pub struct FastLz4CompressedArrayN<N, T> {
pub compressed_bytes: Vec<u8>,
pub extent: ExtentN<N>,
marker: std::marker::PhantomData<T>,
}
impl<N, T> FastLz4CompressedArrayN<N, T> {
pub fn extent(&self) -> &ExtentN<N> {
&self.extent
}
}
impl<N, T> Decompressible<FastLz4> for FastLz4CompressedArrayN<N, T>
where
T: Copy,
ExtentN<N>: IntegerExtent<N>,
{
type Decompressed = ArrayN<N, T>;
fn decompress(&self) -> Self::Decompressed {
let num_points = self.extent.num_points();
let mut decoder = lz4::Decoder::new(self.compressed_bytes.as_slice()).unwrap();
let mut decompressed_values: Vec<T> = Vec::with_capacity(num_points);
unsafe { decompressed_values.set_len(num_points) };
let mut decompressed_slice = unsafe {
std::slice::from_raw_parts_mut(
decompressed_values.as_mut_ptr() as *mut u8,
num_points * core::mem::size_of::<T>(),
)
};
std::io::copy(&mut decoder, &mut decompressed_slice).unwrap();
ArrayN::new(self.extent, decompressed_values)
}
}
impl<N, T> Compressible<FastLz4> for ArrayN<N, T>
where
T: Copy,
ExtentN<N>: IntegerExtent<N>,
{
type Compressed = FastLz4CompressedArrayN<N, T>;
fn compress(&self, params: FastLz4) -> FastLz4CompressedArrayN<N, T> {
let mut compressed_bytes = Vec::new();
let values_slice: &[u8] = unsafe {
std::slice::from_raw_parts(
self.values.as_ptr() as *const u8,
self.values.len() * core::mem::size_of::<T>(),
)
};
let mut encoder = lz4::EncoderBuilder::new()
.level(params.level)
.build(&mut compressed_bytes)
.unwrap();
std::io::copy(&mut std::io::Cursor::new(values_slice), &mut encoder).unwrap();
let (_output, _result) = encoder.finish();
FastLz4CompressedArrayN {
extent: self.extent,
compressed_bytes,
marker: Default::default(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{access::GetUnchecked, copy_extent, Array2, Array3, Get};
use building_blocks_core::{Extent2, Extent3};
#[test]
fn fill_and_get_2d() {
let extent = Extent2::from_min_and_shape(PointN([1, 1]), PointN([10, 10]));
let mut array = Array2::fill(extent, 0);
assert_eq!(array.extent.num_points(), 100);
*array.get_mut(Stride(0)) = 1;
assert_eq!(array.get(Stride(0)), 1);
assert_eq!(array.get_mut(Stride(0)), &mut 1);
assert_eq!(unsafe { array.get_unchecked(Stride(0)) }, 1);
assert_eq!(unsafe { array.get_unchecked_mut(Stride(0)) }, &mut 1);
assert_eq!(array.get(&Local(PointN([0, 0]))), 1);
assert_eq!(array.get_mut(&Local(PointN([0, 0]))), &mut 1);
assert_eq!(unsafe { array.get_unchecked(&Local(PointN([0, 0]))) }, 1);
assert_eq!(
unsafe { array.get_unchecked_mut(&Local(PointN([0, 0]))) },
&mut 1
);
assert_eq!(array.get(&PointN([1, 1])), 1);
assert_eq!(array.get_mut(&PointN([1, 1])), &mut 1);
assert_eq!(unsafe { array.get_unchecked(&PointN([1, 1])) }, 1);
assert_eq!(unsafe { array.get_unchecked_mut(&PointN([1, 1])) }, &mut 1);
}
#[test]
fn fill_and_get_3d() {
let extent = Extent3::from_min_and_shape(PointN([1, 1, 1]), PointN([10, 10, 10]));
let mut array = Array3::fill(extent, 0);
assert_eq!(array.extent.num_points(), 1000);
*array.get_mut(Stride(0)) = 1;
assert_eq!(array.get(Stride(0)), 1);
assert_eq!(array.get_mut(Stride(0)), &mut 1);
assert_eq!(unsafe { array.get_unchecked(Stride(0)) }, 1);
assert_eq!(unsafe { array.get_unchecked_mut(Stride(0)) }, &mut 1);
assert_eq!(array.get(&Local(PointN([0, 0, 0]))), 1);
assert_eq!(array.get_mut(&Local(PointN([0, 0, 0]))), &mut 1);
assert_eq!(unsafe { array.get_unchecked(&Local(PointN([0, 0, 0]))) }, 1);
assert_eq!(
unsafe { array.get_unchecked_mut(&Local(PointN([0, 0, 0]))) },
&mut 1
);
assert_eq!(array.get(&PointN([1, 1, 1])), 1);
assert_eq!(array.get_mut(&PointN([1, 1, 1])), &mut 1);
assert_eq!(unsafe { array.get_unchecked(&PointN([1, 1, 1])) }, 1);
assert_eq!(
unsafe { array.get_unchecked_mut(&PointN([1, 1, 1])) },
&mut 1
);
}
#[test]
fn uninitialized() {
let extent = Extent3::from_min_and_shape(PointN([1, 1, 1]), PointN([10, 10, 10]));
let mut array: Array3<MaybeUninit<i32>> = unsafe { Array3::maybe_uninit(extent) };
for p in extent.iter_points() {
unsafe {
array.get_mut(&p).as_mut_ptr().write(1);
}
}
let array = unsafe { array.assume_init() };
for p in extent.iter_points() {
assert_eq!(array.get(&p), 1i32);
}
}
#[test]
fn copy() {
let extent = Extent3::from_min_and_shape(PointN([0; 3]), PointN([10; 3]));
let mut array = Array3::fill(extent, 0);
let subextent = Extent3::from_min_and_shape(PointN([1; 3]), PointN([5; 3]));
for p in subextent.iter_points() {
*array.get_mut(&p) = p.x() + p.y() + p.z();
}
let mut other_array = Array3::fill(extent, 0);
copy_extent(&subextent, &array, &mut other_array);
assert_eq!(array, other_array);
}
}