use crate::matrices::views::{DataLayout, MatrixMut, MatrixRef, NoInteriorMutability};
use crate::matrices::{Column, Row};
use std::marker::PhantomData;
use std::num::NonZeroUsize;
use std::ops::Range;
#[derive(Clone, Debug)]
pub struct MatrixRange<T, S> {
source: S,
rows: IndexRange,
columns: IndexRange,
_type: PhantomData<T>,
}
#[derive(Clone, Debug)]
pub struct MatrixMask<T, S> {
source: S,
rows: IndexRange,
columns: IndexRange,
_type: PhantomData<T>,
}
impl<T, S> MatrixRange<T, S>
where
S: MatrixRef<T>,
{
pub fn from<R>(source: S, rows: R, columns: R) -> MatrixRange<T, S>
where
R: Into<IndexRange>,
{
let max_rows = source.view_rows();
let max_columns = source.view_columns();
MatrixRange {
source,
rows: {
let mut rows = rows.into();
rows.clip(max_rows);
rows
},
columns: {
let mut columns = columns.into();
columns.clip(max_columns);
columns
},
_type: PhantomData,
}
}
#[allow(dead_code)]
pub fn source(self) -> S {
self.source
}
#[allow(dead_code)]
pub fn source_ref(&self) -> &S {
&self.source
}
}
impl<T, S> MatrixMask<T, S>
where
S: MatrixRef<T>,
{
pub fn from<R>(source: S, rows: R, columns: R) -> MatrixMask<T, S>
where
R: Into<IndexRange>,
{
let max_rows = source.view_rows();
let max_columns = source.view_columns();
MatrixMask {
source,
rows: {
let mut rows = rows.into();
rows.clip(max_rows);
rows
},
columns: {
let mut columns = columns.into();
columns.clip(max_columns);
columns
},
_type: PhantomData,
}
}
pub fn start_and_end_of_rows(source: S, retain: Option<NonZeroUsize>) -> MatrixMask<T, S> {
let rows = match retain {
None => IndexRange::new(0, 0),
Some(x) => {
let x = x.get();
let length = source.view_rows();
let retain_start = std::cmp::min(x, length - 1);
let retain_end = length.saturating_sub(x);
let mut range: IndexRange = (retain_start..retain_end).into();
range.clip(length - 1);
range
}
};
let columns = IndexRange::new(0, 0);
MatrixMask::from(source, rows, columns)
}
pub fn start_and_end_of_columns(source: S, retain: Option<NonZeroUsize>) -> MatrixMask<T, S> {
let rows = IndexRange::new(0, 0);
let columns = match retain {
None => IndexRange::new(0, 0),
Some(x) => {
let x = x.get();
let length = source.view_columns();
let retain_start = std::cmp::min(x, length - 1);
let retain_end = length.saturating_sub(x);
let mut range: IndexRange = (retain_start..retain_end).into();
range.clip(length - 1);
range
}
};
MatrixMask::from(source, rows, columns)
}
#[allow(dead_code)]
pub fn source(self) -> S {
self.source
}
#[allow(dead_code)]
pub fn source_ref(&self) -> &S {
&self.source
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct IndexRange {
pub(crate) start: usize,
pub(crate) length: usize,
}
impl IndexRange {
pub fn new(start: usize, length: usize) -> IndexRange {
IndexRange { start, length }
}
#[inline]
pub(crate) fn map(&self, index: usize) -> Option<usize> {
if index < self.length {
Some(index + self.start)
} else {
None
}
}
#[inline]
pub(crate) fn mask(&self, index: usize) -> usize {
if index < self.start {
index
} else {
index + self.length
}
}
pub(crate) fn clip(&mut self, max_index: usize) {
let end = self.start + self.length;
let end = std::cmp::min(end, max_index);
let length = end.saturating_sub(self.start);
self.length = length;
}
}
impl From<Range<usize>> for IndexRange {
fn from(range: Range<usize>) -> IndexRange {
IndexRange::new(range.start, range.end.saturating_sub(range.start))
}
}
impl From<IndexRange> for Range<usize> {
fn from(range: IndexRange) -> Range<usize> {
Range {
start: range.start,
end: range.start + range.length,
}
}
}
impl From<(usize, usize)> for IndexRange {
fn from(range: (usize, usize)) -> IndexRange {
let (start, length) = range;
IndexRange::new(start, length)
}
}
impl From<[usize; 2]> for IndexRange {
fn from(range: [usize; 2]) -> IndexRange {
let [start, length] = range;
IndexRange::new(start, length)
}
}
#[test]
fn test_index_range_clipping() {
let mut range: IndexRange = (0..6).into();
range.clip(4);
assert_eq!(range, (0..4).into());
let mut range: IndexRange = (1..4).into();
range.clip(5);
assert_eq!(range, (1..4).into());
range.clip(2);
assert_eq!(range, (1..2).into());
let mut range: IndexRange = (3..5).into();
range.clip(2);
assert_eq!(range, (3..2).into());
assert_eq!(range.map(0), None);
assert_eq!(range.map(1), None);
assert_eq!(range.mask(0), 0);
assert_eq!(range.mask(1), 1);
}
unsafe impl<T, S> MatrixRef<T> for MatrixRange<T, S>
where
S: MatrixRef<T>,
{
fn try_get_reference(&self, row: Row, column: Column) -> Option<&T> {
let row = self.rows.map(row)?;
let column = self.columns.map(column)?;
self.source.try_get_reference(row, column)
}
fn view_rows(&self) -> Row {
self.rows.length
}
fn view_columns(&self) -> Column {
self.columns.length
}
unsafe fn get_reference_unchecked(&self, row: Row, column: Column) -> &T {
unsafe {
let row = self.rows.map(row).unwrap();
let column = self.columns.map(column).unwrap();
self.source.get_reference_unchecked(row, column)
}
}
fn data_layout(&self) -> DataLayout {
self.source.data_layout()
}
}
unsafe impl<T, S> MatrixMut<T> for MatrixRange<T, S>
where
S: MatrixMut<T>,
{
fn try_get_reference_mut(&mut self, row: Row, column: Column) -> Option<&mut T> {
let row = self.rows.map(row)?;
let column = self.columns.map(column)?;
self.source.try_get_reference_mut(row, column)
}
unsafe fn get_reference_unchecked_mut(&mut self, row: Row, column: Column) -> &mut T {
unsafe {
let row = self.rows.map(row).unwrap();
let column = self.columns.map(column).unwrap();
self.source.get_reference_unchecked_mut(row, column)
}
}
}
unsafe impl<T, S> NoInteriorMutability for MatrixRange<T, S> where S: NoInteriorMutability {}
#[test]
fn test_matrix_range_shape_clips() {
use crate::matrices::Matrix;
let matrix = Matrix::from(vec![vec![1, 2, 3], vec![4, 5, 6]]);
let range = MatrixRange::from(&matrix, 0..7, 1..4);
assert_eq!(2, range.view_rows());
assert_eq!(2, range.view_columns());
assert_eq!(2, range.rows.length);
assert_eq!(2, range.columns.length);
}
unsafe impl<T, S> MatrixRef<T> for MatrixMask<T, S>
where
S: MatrixRef<T>,
{
fn try_get_reference(&self, row: Row, column: Column) -> Option<&T> {
let row = self.rows.mask(row);
let column = self.columns.mask(column);
self.source.try_get_reference(row, column)
}
fn view_rows(&self) -> Row {
self.source.view_rows() - self.rows.length
}
fn view_columns(&self) -> Column {
self.source.view_columns() - self.columns.length
}
unsafe fn get_reference_unchecked(&self, row: Row, column: Column) -> &T {
unsafe {
let row = self.rows.mask(row);
let column = self.columns.mask(column);
self.source.get_reference_unchecked(row, column)
}
}
fn data_layout(&self) -> DataLayout {
self.source.data_layout()
}
}
unsafe impl<T, S> MatrixMut<T> for MatrixMask<T, S>
where
S: MatrixMut<T>,
{
fn try_get_reference_mut(&mut self, row: Row, column: Column) -> Option<&mut T> {
let row = self.rows.mask(row);
let column = self.columns.mask(column);
self.source.try_get_reference_mut(row, column)
}
unsafe fn get_reference_unchecked_mut(&mut self, row: Row, column: Column) -> &mut T {
unsafe {
let row = self.rows.mask(row);
let column = self.columns.mask(column);
self.source.get_reference_unchecked_mut(row, column)
}
}
}
unsafe impl<T, S> NoInteriorMutability for MatrixMask<T, S> where S: NoInteriorMutability {}