rlst 0.10.0

A Rust native linear algebra library.
Documentation
//! Reverse a single axis of an array.

use crate::ContainerType;
use crate::dense::array::Array;
use crate::dense::layout::convert_1d_nd_from_shape;
use crate::traits::accessors::{
    UnsafeRandom1DAccessByRef, UnsafeRandom1DAccessByValue, UnsafeRandom1DAccessMut,
    UnsafeRandomAccessByRef, UnsafeRandomAccessByValue, UnsafeRandomAccessMut,
};
use crate::traits::base_operations::{BaseItem, Shape};

/// This struct represents an array implementation with a single axis reversed.
pub struct ReverseAxis<ArrayImpl, const NDIM: usize> {
    arr: Array<ArrayImpl, NDIM>,
    axis: usize,
}

impl<ArrayImpl, const NDIM: usize> ReverseAxis<ArrayImpl, NDIM> {
    /// Create a lazy view that reverses `axis`.
    ///
    /// `axis` must be less than `NDIM`; prefer [`Array::reverse_axis`], which checks this
    /// requirement immediately.
    pub fn new(arr: Array<ArrayImpl, NDIM>, axis: usize) -> Self {
        Self { arr, axis }
    }
}

impl<ArrayImpl, const NDIM: usize> Shape<NDIM> for ReverseAxis<ArrayImpl, NDIM>
where
    ArrayImpl: Shape<NDIM>,
{
    #[inline(always)]
    fn shape(&self) -> [usize; NDIM] {
        self.arr.shape()
    }
}

impl<ArrayImpl, const NDIM: usize> ContainerType for ReverseAxis<ArrayImpl, NDIM>
where
    ArrayImpl: ContainerType,
{
    type Type = ArrayImpl::Type;
}

impl<Item, ArrayImpl, const NDIM: usize> BaseItem for ReverseAxis<ArrayImpl, NDIM>
where
    ArrayImpl: BaseItem<Item = Item>,
    Item: Copy + Default,
{
    type Item = Item;
}

impl<ArrayImpl, const NDIM: usize> UnsafeRandomAccessByValue<NDIM> for ReverseAxis<ArrayImpl, NDIM>
where
    ArrayImpl: UnsafeRandomAccessByValue<NDIM> + Shape<NDIM>,
{
    #[inline(always)]
    unsafe fn get_value_unchecked(&self, multi_index: [usize; NDIM]) -> Self::Item {
        unsafe {
            self.arr.get_value_unchecked(reverse_multi_index(
                multi_index,
                self.axis,
                self.arr.shape(),
            ))
        }
    }
}

impl<ArrayImpl, const NDIM: usize> UnsafeRandomAccessByRef<NDIM> for ReverseAxis<ArrayImpl, NDIM>
where
    ArrayImpl: UnsafeRandomAccessByRef<NDIM> + Shape<NDIM>,
{
    #[inline(always)]
    unsafe fn get_unchecked(&self, multi_index: [usize; NDIM]) -> &Self::Item {
        unsafe {
            self.arr.get_unchecked(reverse_multi_index(
                multi_index,
                self.axis,
                self.arr.shape(),
            ))
        }
    }
}

impl<ArrayImpl, const NDIM: usize> UnsafeRandomAccessMut<NDIM> for ReverseAxis<ArrayImpl, NDIM>
where
    ArrayImpl: UnsafeRandomAccessMut<NDIM> + Shape<NDIM>,
{
    #[inline(always)]
    unsafe fn get_unchecked_mut(&mut self, multi_index: [usize; NDIM]) -> &mut Self::Item {
        unsafe {
            self.arr.get_unchecked_mut(reverse_multi_index(
                multi_index,
                self.axis,
                self.arr.shape(),
            ))
        }
    }
}

impl<ArrayImpl, const NDIM: usize> UnsafeRandom1DAccessByValue for ReverseAxis<ArrayImpl, NDIM>
where
    ArrayImpl: UnsafeRandomAccessByValue<NDIM> + Shape<NDIM>,
{
    #[inline(always)]
    unsafe fn get_value_1d_unchecked(&self, index: usize) -> Self::Item {
        let multi_index = convert_1d_nd_from_shape(index, self.arr.shape());
        unsafe { self.get_value_unchecked(multi_index) }
    }
}

impl<ArrayImpl, const NDIM: usize> UnsafeRandom1DAccessByRef for ReverseAxis<ArrayImpl, NDIM>
where
    ArrayImpl: UnsafeRandomAccessByRef<NDIM> + Shape<NDIM>,
{
    #[inline(always)]
    unsafe fn get_1d_unchecked(&self, index: usize) -> &Self::Item {
        let multi_index = convert_1d_nd_from_shape(index, self.arr.shape());
        unsafe { self.get_unchecked(multi_index) }
    }
}

impl<ArrayImpl, const NDIM: usize> UnsafeRandom1DAccessMut for ReverseAxis<ArrayImpl, NDIM>
where
    ArrayImpl: UnsafeRandomAccessMut<NDIM> + Shape<NDIM>,
{
    #[inline(always)]
    unsafe fn get_1d_unchecked_mut(&mut self, index: usize) -> &mut Self::Item {
        let multi_index = convert_1d_nd_from_shape(index, self.arr.shape());
        unsafe { self.get_unchecked_mut(multi_index) }
    }
}

#[inline(always)]
fn reverse_multi_index<const NDIM: usize>(
    mut multi_index: [usize; NDIM],
    axis: usize,
    shape: [usize; NDIM],
) -> [usize; NDIM] {
    multi_index[axis] = shape[axis] - 1 - multi_index[axis];
    multi_index
}

// SAFETY: reversing an axis is an injective permutation of source indices.
unsafe impl<ArrayImpl, const NDIM: usize> crate::UnsafeDisjointRandom1DAccessMut
    for ReverseAxis<ArrayImpl, NDIM>
where
    ArrayImpl: crate::UnsafeDisjointRandom1DAccessMut + UnsafeRandomAccessMut<NDIM> + Shape<NDIM>,
{
}