use super::Matrix;
use super::layout::Stride;
use super::order::{Order, OrderKind};
use crate::error::Result;
use crate::index::{AsIndex, Index, MatrixIndex, WrappingIndex};
impl<T, O> Matrix<T, O>
where
O: Order,
{
pub fn get<I>(&self, index: I) -> Result<&I::Output>
where
I: MatrixIndex<Self>,
{
index.get(self)
}
pub fn get_mut<I>(&mut self, index: I) -> Result<&mut I::Output>
where
I: MatrixIndex<Self>,
{
index.get_mut(self)
}
pub unsafe fn get_unchecked<I>(&self, index: I) -> &I::Output
where
I: MatrixIndex<Self>,
{
unsafe { &*index.get_unchecked(self) }
}
pub unsafe fn get_unchecked_mut<I>(&mut self, index: I) -> &mut I::Output
where
I: MatrixIndex<Self>,
{
unsafe { &mut *index.get_unchecked_mut(self) }
}
}
impl<T, O, I> core::ops::Index<I> for Matrix<T, O>
where
O: Order,
I: MatrixIndex<Self, Output = T>,
{
type Output = I::Output;
fn index(&self, index: I) -> &Self::Output {
match self.get(index) {
Err(error) => panic!("{error}"),
Ok(output) => output,
}
}
}
impl<T, O, I> core::ops::IndexMut<I> for Matrix<T, O>
where
O: Order,
I: MatrixIndex<Self, Output = T>,
{
fn index_mut(&mut self, index: I) -> &mut Self::Output {
match self.get_mut(index) {
Err(error) => panic!("{error}"),
Ok(output) => output,
}
}
}
unsafe impl<T, O, I> MatrixIndex<Matrix<T, O>> for I
where
O: Order,
I: AsIndex,
{
type Output = T;
fn is_out_of_bounds(&self, matrix: &Matrix<T, O>) -> bool {
let shape = matrix.shape();
self.row() >= shape.nrows || self.col() >= shape.ncols
}
unsafe fn get_unchecked(self, matrix: *const Matrix<T, O>) -> *const Self::Output {
let matrix = unsafe { &*matrix };
let stride = matrix.stride();
let index = Index::new(self.row(), self.col()).to_flattened::<O>(stride);
unsafe { matrix.data.as_ptr().add(index) }
}
unsafe fn get_unchecked_mut(self, matrix: *mut Matrix<T, O>) -> *mut Self::Output {
let matrix = unsafe { &mut *matrix };
let stride = matrix.stride();
let index = Index::new(self.row(), self.col()).to_flattened::<O>(stride);
unsafe { matrix.data.as_mut_ptr().add(index) }
}
}
unsafe impl<T, O> MatrixIndex<Matrix<T, O>> for WrappingIndex
where
O: Order,
{
type Output = T;
fn is_out_of_bounds(&self, matrix: &Matrix<T, O>) -> bool {
matrix.is_empty()
}
unsafe fn get_unchecked(self, matrix: *const Matrix<T, O>) -> *const Self::Output {
let matrix = unsafe { &*matrix };
let shape = matrix.shape();
let index = Index::from_wrapping_index(self, shape);
unsafe { index.get_unchecked(matrix) }
}
unsafe fn get_unchecked_mut(self, matrix: *mut Matrix<T, O>) -> *mut Self::Output {
let matrix = unsafe { &mut *matrix };
let shape = matrix.shape();
let index = Index::from_wrapping_index(self, shape);
unsafe { index.get_unchecked_mut(matrix) }
}
}
impl Index {
pub(super) fn from_flattened<O>(index: usize, stride: Stride) -> Self
where
O: Order,
{
let major = index / stride.major();
let minor = (index % stride.major()) / stride.minor();
match O::KIND {
OrderKind::RowMajor => Self::new(major, minor),
OrderKind::ColMajor => Self::new(minor, major),
}
}
pub(super) fn to_flattened<O>(self, stride: Stride) -> usize
where
O: Order,
{
let (major, minor) = match O::KIND {
OrderKind::RowMajor => (self.row, self.col),
OrderKind::ColMajor => (self.col, self.row),
};
major * stride.major() + minor * stride.minor()
}
}
#[cfg(test)]
mod tests {
use super::super::order::{ColMajor, RowMajor};
use super::*;
use crate::error::Error;
use crate::{dispatch_unary, matrix};
#[test]
fn test_matrix_get() -> Result<()> {
dispatch_unary! {{
let matrix = matrix![[1, 2, 3], [4, 5, 6]].with_order::<O>();
assert_eq!(*matrix.get(Index::new(0, 0))?, 1);
assert_eq!(*matrix.get(Index::new(0, 1))?, 2);
assert_eq!(*matrix.get(Index::new(0, 2))?, 3);
assert_eq!(*matrix.get(Index::new(1, 0))?, 4);
assert_eq!(*matrix.get(Index::new(1, 1))?, 5);
assert_eq!(*matrix.get(Index::new(1, 2))?, 6);
assert_eq!(matrix.get(Index::new(2, 0)), Err(Error::IndexOutOfBounds));
assert_eq!(matrix.get(Index::new(0, 3)), Err(Error::IndexOutOfBounds));
assert_eq!(matrix.get(Index::new(2, 3)), Err(Error::IndexOutOfBounds));
}}
Ok(())
}
#[test]
fn test_matrix_get_mut() -> Result<()> {
dispatch_unary! {{
let mut matrix = matrix![[1, 2, 3], [4, 5, 6]].with_order::<O>();
*matrix.get_mut(Index::new(0, 0))? -= 1;
*matrix.get_mut(Index::new(0, 1))? -= 2;
*matrix.get_mut(Index::new(0, 2))? -= 3;
*matrix.get_mut(Index::new(1, 0))? -= 4;
*matrix.get_mut(Index::new(1, 1))? -= 5;
*matrix.get_mut(Index::new(1, 2))? -= 6;
let expected = matrix![[0, 0, 0], [0, 0, 0]];
assert_eq!(matrix, expected);
assert_eq!(
matrix.get_mut(Index::new(2, 0)),
Err(Error::IndexOutOfBounds)
);
assert_eq!(
matrix.get_mut(Index::new(0, 3)),
Err(Error::IndexOutOfBounds)
);
assert_eq!(
matrix.get_mut(Index::new(2, 3)),
Err(Error::IndexOutOfBounds)
);
}}
Ok(())
}
#[test]
fn test_matrix_get_unchecked() {
dispatch_unary! {{
unsafe {
let matrix = matrix![[1, 2, 3], [4, 5, 6]].with_order::<O>();
assert_eq!(*matrix.get_unchecked(Index::new(0, 0)), 1);
assert_eq!(*matrix.get_unchecked(Index::new(0, 1)), 2);
assert_eq!(*matrix.get_unchecked(Index::new(0, 2)), 3);
assert_eq!(*matrix.get_unchecked(Index::new(1, 0)), 4);
assert_eq!(*matrix.get_unchecked(Index::new(1, 1)), 5);
assert_eq!(*matrix.get_unchecked(Index::new(1, 2)), 6);
}
}}
}
#[test]
fn test_matrix_get_unchecked_mut() {
dispatch_unary! {{
unsafe {
let mut matrix = matrix![[1, 2, 3], [4, 5, 6]].with_order::<O>();
*matrix.get_unchecked_mut(Index::new(0, 0)) -= 1;
*matrix.get_unchecked_mut(Index::new(0, 1)) -= 2;
*matrix.get_unchecked_mut(Index::new(0, 2)) -= 3;
*matrix.get_unchecked_mut(Index::new(1, 0)) -= 4;
*matrix.get_unchecked_mut(Index::new(1, 1)) -= 5;
*matrix.get_unchecked_mut(Index::new(1, 2)) -= 6;
let expected = matrix![[0, 0, 0], [0, 0, 0]];
assert_eq!(matrix, expected);
}
}}
}
#[test]
fn test_matrix_index() {
dispatch_unary! {{
let matrix = matrix![[1, 2, 3], [4, 5, 6]].with_order::<O>();
assert_eq!(matrix[Index::new(0, 0)], 1);
assert_eq!(matrix[Index::new(0, 1)], 2);
assert_eq!(matrix[Index::new(0, 2)], 3);
assert_eq!(matrix[Index::new(1, 0)], 4);
assert_eq!(matrix[Index::new(1, 1)], 5);
assert_eq!(matrix[Index::new(1, 2)], 6);
}}
}
#[test]
#[should_panic]
fn test_matrix_index_out_of_bounds_row_major() {
let matrix = matrix![[1, 2, 3], [4, 5, 6]].with_order::<RowMajor>();
let _ = matrix[Index::new(2, 3)];
}
#[test]
#[should_panic]
fn test_matrix_index_out_of_bounds_col_major() {
let matrix = matrix![[1, 2, 3], [4, 5, 6]].with_order::<ColMajor>();
let _ = matrix[Index::new(2, 3)];
}
#[test]
fn test_matrix_index_mut() {
dispatch_unary! {{
let mut matrix = matrix![[1, 2, 3], [4, 5, 6]].with_order::<O>();
matrix[Index::new(0, 0)] -= 1;
matrix[Index::new(0, 1)] -= 2;
matrix[Index::new(0, 2)] -= 3;
matrix[Index::new(1, 0)] -= 4;
matrix[Index::new(1, 1)] -= 5;
matrix[Index::new(1, 2)] -= 6;
let expected = matrix![[0, 0, 0], [0, 0, 0]];
assert_eq!(matrix, expected);
}}
}
#[test]
#[should_panic]
fn test_matrix_index_mut_out_of_bounds_row_major() {
let mut matrix = matrix![[1, 2, 3], [4, 5, 6]].with_order::<RowMajor>();
matrix[Index::new(2, 3)] += 2;
}
#[test]
#[should_panic]
fn test_matrix_index_mut_out_of_bounds_col_major() {
let mut matrix = matrix![[1, 2, 3], [4, 5, 6]].with_order::<ColMajor>();
matrix[Index::new(2, 3)] += 2;
}
#[test]
fn test_as_index_is_out_of_bounds() {
dispatch_unary! {{
let matrix = matrix![[1, 2, 3], [4, 5, 6]].with_order::<O>();
assert!(!Index::new(0, 0).is_out_of_bounds(&matrix));
assert!(!Index::new(0, 1).is_out_of_bounds(&matrix));
assert!(!Index::new(0, 2).is_out_of_bounds(&matrix));
assert!(!Index::new(1, 0).is_out_of_bounds(&matrix));
assert!(!Index::new(1, 1).is_out_of_bounds(&matrix));
assert!(!Index::new(1, 2).is_out_of_bounds(&matrix));
assert!(Index::new(2, 0).is_out_of_bounds(&matrix));
assert!(Index::new(0, 3).is_out_of_bounds(&matrix));
assert!(Index::new(2, 3).is_out_of_bounds(&matrix));
}}
}
#[test]
fn test_as_index_ensure_in_bounds() {
dispatch_unary! {{
let matrix = matrix![[1, 2, 3], [4, 5, 6]].with_order::<O>();
assert!(Index::new(0, 0).ensure_in_bounds(&matrix).is_ok());
assert!(Index::new(0, 1).ensure_in_bounds(&matrix).is_ok());
assert!(Index::new(0, 2).ensure_in_bounds(&matrix).is_ok());
assert!(Index::new(1, 0).ensure_in_bounds(&matrix).is_ok());
assert!(Index::new(1, 1).ensure_in_bounds(&matrix).is_ok());
assert!(Index::new(1, 2).ensure_in_bounds(&matrix).is_ok());
assert_eq!(
Index::new(2, 0).ensure_in_bounds(&matrix),
Err(Error::IndexOutOfBounds)
);
assert_eq!(
Index::new(0, 3).ensure_in_bounds(&matrix),
Err(Error::IndexOutOfBounds)
);
assert_eq!(
Index::new(2, 3).ensure_in_bounds(&matrix),
Err(Error::IndexOutOfBounds)
);
}}
}
#[test]
fn test_as_index_get() -> Result<()> {
dispatch_unary! {{
let matrix = matrix![[1, 2, 3], [4, 5, 6]].with_order::<O>();
assert_eq!(*Index::new(0, 0).get(&matrix)?, 1);
assert_eq!(*Index::new(0, 1).get(&matrix)?, 2);
assert_eq!(*Index::new(0, 2).get(&matrix)?, 3);
assert_eq!(*Index::new(1, 0).get(&matrix)?, 4);
assert_eq!(*Index::new(1, 1).get(&matrix)?, 5);
assert_eq!(*Index::new(1, 2).get(&matrix)?, 6);
assert_eq!(Index::new(2, 0).get(&matrix), Err(Error::IndexOutOfBounds));
assert_eq!(Index::new(0, 3).get(&matrix), Err(Error::IndexOutOfBounds));
assert_eq!(Index::new(2, 3).get(&matrix), Err(Error::IndexOutOfBounds));
}}
Ok(())
}
#[test]
fn test_as_index_get_mut() -> Result<()> {
dispatch_unary! {{
let mut matrix = matrix![[1, 2, 3], [4, 5, 6]].with_order::<O>();
*Index::new(0, 0).get_mut(&mut matrix)? -= 1;
*Index::new(0, 1).get_mut(&mut matrix)? -= 2;
*Index::new(0, 2).get_mut(&mut matrix)? -= 3;
*Index::new(1, 0).get_mut(&mut matrix)? -= 4;
*Index::new(1, 1).get_mut(&mut matrix)? -= 5;
*Index::new(1, 2).get_mut(&mut matrix)? -= 6;
let expected = matrix![[0, 0, 0], [0, 0, 0]];
assert_eq!(matrix, expected);
assert_eq!(Index::new(2, 0).get_mut(&mut matrix), Err(Error::IndexOutOfBounds));
assert_eq!(Index::new(0, 3).get_mut(&mut matrix), Err(Error::IndexOutOfBounds));
assert_eq!(Index::new(2, 3).get_mut(&mut matrix), Err(Error::IndexOutOfBounds));
}}
Ok(())
}
#[test]
fn test_as_index_get_unchecked() {
dispatch_unary! {{
unsafe {
let matrix = matrix![[1, 2, 3], [4, 5, 6]].with_order::<O>();
assert_eq!(*Index::new(0, 0).get_unchecked(&matrix), 1);
assert_eq!(*Index::new(0, 1).get_unchecked(&matrix), 2);
assert_eq!(*Index::new(0, 2).get_unchecked(&matrix), 3);
assert_eq!(*Index::new(1, 0).get_unchecked(&matrix), 4);
assert_eq!(*Index::new(1, 1).get_unchecked(&matrix), 5);
assert_eq!(*Index::new(1, 2).get_unchecked(&matrix), 6);
}
}}
}
#[test]
fn test_as_index_get_unchecked_mut() {
dispatch_unary! {{
unsafe {
let mut matrix = matrix![[1, 2, 3], [4, 5, 6]].with_order::<O>();
*Index::new(0, 0).get_unchecked_mut(&mut matrix) -= 1;
*Index::new(0, 1).get_unchecked_mut(&mut matrix) -= 2;
*Index::new(0, 2).get_unchecked_mut(&mut matrix) -= 3;
*Index::new(1, 0).get_unchecked_mut(&mut matrix) -= 4;
*Index::new(1, 1).get_unchecked_mut(&mut matrix) -= 5;
*Index::new(1, 2).get_unchecked_mut(&mut matrix) -= 6;
let expected = matrix![[0, 0, 0], [0, 0, 0]];
assert_eq!(matrix, expected);
}
}}
}
#[test]
fn test_wrapping_index_is_out_of_bounds() {
dispatch_unary! {{
let matrix = matrix![[1, 2, 3], [4, 5, 6]].with_order::<O>();
for row in (-6..=6).step_by(2) {
for col in (-6..=6).step_by(3) {
assert!(!WrappingIndex::new(row, col).is_out_of_bounds(&matrix));
}
}
let matrix = Matrix::<i32, O>::new();
for row in (-6..=6).step_by(2) {
for col in (-6..=6).step_by(3) {
assert!(WrappingIndex::new(row, col).is_out_of_bounds(&matrix));
}
}
}}
}
#[test]
fn test_wrapping_index_ensure_in_bounds() {
dispatch_unary! {{
let matrix = matrix![[1, 2, 3], [4, 5, 6]].with_order::<O>();
for row in (-6..=6).step_by(2) {
for col in (-6..=6).step_by(3) {
assert!(
WrappingIndex::new(row, col)
.ensure_in_bounds(&matrix)
.is_ok()
);
}
}
let matrix = Matrix::<i32, O>::new();
for row in (-6..=6).step_by(2) {
for col in (-6..=6).step_by(3) {
assert_eq!(
WrappingIndex::new(row, col).ensure_in_bounds(&matrix),
Err(Error::IndexOutOfBounds)
);
}
}
}}
}
#[test]
fn test_wrapping_index_get() -> Result<()> {
dispatch_unary! {{
let matrix = matrix![[1, 2, 3], [4, 5, 6]].with_order::<O>();
assert_eq!(*WrappingIndex::new(0, 0).get(&matrix)?, 1);
assert_eq!(*WrappingIndex::new(0, 1).get(&matrix)?, 2);
assert_eq!(*WrappingIndex::new(0, 2).get(&matrix)?, 3);
assert_eq!(*WrappingIndex::new(1, 0).get(&matrix)?, 4);
assert_eq!(*WrappingIndex::new(1, 1).get(&matrix)?, 5);
assert_eq!(*WrappingIndex::new(1, 2).get(&matrix)?, 6);
for row in (-6..=6).step_by(2) {
for col in (-6..=6).step_by(3) {
assert_eq!(*WrappingIndex::new(row, col).get(&matrix)?, 1);
}
}
let matrix = Matrix::<i32, O>::new();
assert_eq!(
WrappingIndex::new(0, 0).get(&matrix),
Err(Error::IndexOutOfBounds)
);
assert_eq!(
WrappingIndex::new(0, 1).get(&matrix),
Err(Error::IndexOutOfBounds)
);
assert_eq!(
WrappingIndex::new(0, 2).get(&matrix),
Err(Error::IndexOutOfBounds)
);
assert_eq!(
WrappingIndex::new(1, 0).get(&matrix),
Err(Error::IndexOutOfBounds)
);
assert_eq!(
WrappingIndex::new(1, 1).get(&matrix),
Err(Error::IndexOutOfBounds)
);
assert_eq!(
WrappingIndex::new(1, 2).get(&matrix),
Err(Error::IndexOutOfBounds)
);
for row in (-6..=6).step_by(2) {
for col in (-6..=6).step_by(3) {
assert_eq!(
WrappingIndex::new(row, col).get(&matrix),
Err(Error::IndexOutOfBounds)
);
}
}
}}
Ok(())
}
#[test]
fn test_wrapping_index_get_mut() -> Result<()> {
dispatch_unary! {{
let mut matrix = matrix![[1, 2, 3], [4, 5, 6]].with_order::<O>();
*WrappingIndex::new(0, 0).get_mut(&mut matrix)? -= 1;
*WrappingIndex::new(0, 1).get_mut(&mut matrix)? -= 2;
*WrappingIndex::new(0, 2).get_mut(&mut matrix)? -= 3;
*WrappingIndex::new(1, 0).get_mut(&mut matrix)? -= 4;
*WrappingIndex::new(1, 1).get_mut(&mut matrix)? -= 5;
*WrappingIndex::new(1, 2).get_mut(&mut matrix)? -= 6;
for row in (-6..=6).step_by(2) {
for col in (-6..=6).step_by(3) {
*WrappingIndex::new(row, col).get_mut(&mut matrix)? -= 1;
}
}
let expected = matrix![[-35, 0, 0], [0, 0, 0]];
assert_eq!(matrix, expected);
let mut matrix = Matrix::<i32, O>::new();
assert_eq!(
WrappingIndex::new(0, 0).get_mut(&mut matrix),
Err(Error::IndexOutOfBounds)
);
assert_eq!(
WrappingIndex::new(0, 1).get_mut(&mut matrix),
Err(Error::IndexOutOfBounds)
);
assert_eq!(
WrappingIndex::new(0, 2).get_mut(&mut matrix),
Err(Error::IndexOutOfBounds)
);
assert_eq!(
WrappingIndex::new(1, 0).get_mut(&mut matrix),
Err(Error::IndexOutOfBounds)
);
assert_eq!(
WrappingIndex::new(1, 1).get_mut(&mut matrix),
Err(Error::IndexOutOfBounds)
);
assert_eq!(
WrappingIndex::new(1, 2).get_mut(&mut matrix),
Err(Error::IndexOutOfBounds)
);
for row in (-6..=6).step_by(2) {
for col in (-6..=6).step_by(3) {
assert_eq!(
WrappingIndex::new(row, col).get_mut(&mut matrix),
Err(Error::IndexOutOfBounds)
);
}
}
}}
Ok(())
}
#[test]
fn test_wrapping_index_get_unchecked() {
dispatch_unary! {{
unsafe {
let matrix = matrix![[1, 2, 3], [4, 5, 6]].with_order::<O>();
assert_eq!(*WrappingIndex::new(0, 0).get_unchecked(&matrix), 1);
assert_eq!(*WrappingIndex::new(0, 1).get_unchecked(&matrix), 2);
assert_eq!(*WrappingIndex::new(0, 2).get_unchecked(&matrix), 3);
assert_eq!(*WrappingIndex::new(1, 0).get_unchecked(&matrix), 4);
assert_eq!(*WrappingIndex::new(1, 1).get_unchecked(&matrix), 5);
assert_eq!(*WrappingIndex::new(1, 2).get_unchecked(&matrix), 6);
for row in (-6..=6).step_by(2) {
for col in (-6..=6).step_by(3) {
assert_eq!(*WrappingIndex::new(row, col).get_unchecked(&matrix), 1);
}
}
}
}}
}
#[test]
#[should_panic]
fn test_wrapping_index_get_unchecked_fails_row_major() {
unsafe {
let matrix = Matrix::<i32, RowMajor>::new();
WrappingIndex::new(0, 0).get_unchecked(&matrix);
}
}
#[test]
#[should_panic]
fn test_wrapping_index_get_unchecked_fails_col_major() {
unsafe {
let matrix = Matrix::<i32, ColMajor>::new();
WrappingIndex::new(0, 0).get_unchecked(&matrix);
}
}
#[test]
fn test_wrapping_index_get_unchecked_mut() {
dispatch_unary! {{
unsafe {
let mut matrix = matrix![[1, 2, 3], [4, 5, 6]].with_order::<O>();
*WrappingIndex::new(0, 0).get_unchecked_mut(&mut matrix) -= 1;
*WrappingIndex::new(0, 1).get_unchecked_mut(&mut matrix) -= 2;
*WrappingIndex::new(0, 2).get_unchecked_mut(&mut matrix) -= 3;
*WrappingIndex::new(1, 0).get_unchecked_mut(&mut matrix) -= 4;
*WrappingIndex::new(1, 1).get_unchecked_mut(&mut matrix) -= 5;
*WrappingIndex::new(1, 2).get_unchecked_mut(&mut matrix) -= 6;
for row in (-6..=6).step_by(2) {
for col in (-6..=6).step_by(3) {
*WrappingIndex::new(row, col).get_unchecked_mut(&mut matrix) -= 1;
}
}
let expected = matrix![[-35, 0, 0], [0, 0, 0]];
assert_eq!(matrix, expected);
}
}}
}
#[test]
#[should_panic]
fn test_wrapping_index_get_unchecked_mut_fails_row_major() {
unsafe {
let mut matrix = Matrix::<i32, RowMajor>::new();
*WrappingIndex::new(0, 0).get_unchecked_mut(&mut matrix) += 2;
}
}
#[test]
#[should_panic]
fn test_wrapping_index_get_unchecked_mut_fails_col_major() {
unsafe {
let mut matrix = Matrix::<i32, ColMajor>::new();
*WrappingIndex::new(0, 0).get_unchecked_mut(&mut matrix) += 2;
}
}
}