use super::Matrix;
use super::MatrixSlice;
use super::MatrixSliceMut;
use std::marker::PhantomData;
use std::mem;
pub trait BaseSlice<T> {
fn rows(&self) -> usize;
fn cols(&self) -> usize;
fn row_stride(&self) -> usize;
fn as_ptr(&self) -> *const T;
unsafe fn get_unchecked(&self, index: [usize; 2]) -> &T;
}
impl<'a, T> BaseSlice<T> for MatrixSlice<'a, T> {
fn rows(&self) -> usize {
self.rows
}
fn cols(&self) -> usize {
self.cols
}
fn row_stride(&self) -> usize {
self.row_stride
}
fn as_ptr(&self) -> *const T {
self.ptr
}
unsafe fn get_unchecked(&self, index: [usize; 2]) -> &T {
&*(self.ptr.offset((index[0] * self.row_stride + index[1]) as isize))
}
}
impl<'a, T> BaseSlice<T> for MatrixSliceMut<'a, T> {
fn rows(&self) -> usize {
self.rows
}
fn cols(&self) -> usize {
self.cols
}
fn row_stride(&self) -> usize {
self.row_stride
}
fn as_ptr(&self) -> *const T {
self.ptr as *const T
}
unsafe fn get_unchecked(&self, index: [usize; 2]) -> &T {
&*(self.ptr.offset((index[0] * self.row_stride + index[1]) as isize))
}
}
impl<'a, T> MatrixSlice<'a, T> {
pub fn from_matrix(mat: &'a Matrix<T>,
start: [usize; 2],
rows: usize,
cols: usize)
-> MatrixSlice<T> {
assert!(start[0] + rows <= mat.rows(),
"View dimensions exceed matrix dimensions.");
assert!(start[1] + cols <= mat.cols(),
"View dimensions exceed matrix dimensions.");
unsafe {
MatrixSlice {
ptr: mat.data().get_unchecked(start[0] * mat.cols + start[1]) as *const T,
rows: rows,
cols: cols,
row_stride: mat.cols,
marker: PhantomData::<&'a T>,
}
}
}
pub unsafe fn from_raw_parts(ptr: *const T,
rows: usize,
cols: usize,
row_stride: usize)
-> MatrixSlice<'a, T> {
MatrixSlice {
ptr: ptr,
rows: rows,
cols: cols,
row_stride: row_stride,
marker: PhantomData::<&'a T>,
}
}
pub fn reslice(mut self, start: [usize; 2], rows: usize, cols: usize) -> MatrixSlice<'a, T> {
assert!(start[0] + rows <= self.rows,
"View dimensions exceed matrix dimensions.");
assert!(start[1] + cols <= self.cols,
"View dimensions exceed matrix dimensions.");
unsafe {
self.ptr = self.ptr.offset((start[0] * self.cols + start[1]) as isize);
}
self.rows = rows;
self.cols = cols;
self
}
pub fn iter(&self) -> SliceIter<T> {
SliceIter {
slice_start: self.ptr,
row_pos: 0,
col_pos: 0,
slice_rows: self.rows,
slice_cols: self.cols,
row_stride: self.row_stride,
_marker: PhantomData::<&'a T>,
}
}
}
impl<'a, T: Copy> MatrixSlice<'a, T> {
pub fn into_matrix(self) -> Matrix<T> {
self.iter_rows().collect::<Matrix<T>>()
}
}
impl<'a, T> MatrixSliceMut<'a, T> {
pub fn from_matrix(mat: &'a mut Matrix<T>,
start: [usize; 2],
rows: usize,
cols: usize)
-> MatrixSliceMut<T> {
assert!(start[0] + rows <= mat.rows(),
"View dimensions exceed matrix dimensions.");
assert!(start[1] + cols <= mat.cols(),
"View dimensions exceed matrix dimensions.");
let mat_cols = mat.cols();
unsafe {
MatrixSliceMut {
ptr: mat.mut_data().get_unchecked_mut(start[0] * mat_cols + start[1]) as *mut T,
rows: rows,
cols: cols,
row_stride: mat_cols,
marker: PhantomData::<&'a mut T>,
}
}
}
pub unsafe fn from_raw_parts(ptr: *mut T,
rows: usize,
cols: usize,
row_stride: usize)
-> MatrixSliceMut<'a, T> {
MatrixSliceMut {
ptr: ptr,
rows: rows,
cols: cols,
row_stride: row_stride,
marker: PhantomData::<&'a mut T>,
}
}
pub fn reslice(mut self, start: [usize; 2], rows: usize, cols: usize) -> MatrixSliceMut<'a, T> {
assert!(start[0] + rows <= self.rows,
"View dimensions exceed matrix dimensions.");
assert!(start[1] + cols <= self.cols,
"View dimensions exceed matrix dimensions.");
unsafe {
self.ptr = self.ptr.offset((start[0] * self.cols + start[1]) as isize);
}
self.rows = rows;
self.cols = cols;
self
}
pub fn iter(&self) -> SliceIter<T> {
SliceIter {
slice_start: self.ptr as *const T,
row_pos: 0,
col_pos: 0,
slice_rows: self.rows,
slice_cols: self.cols,
row_stride: self.row_stride,
_marker: PhantomData::<&T>,
}
}
pub fn iter_mut(&mut self) -> SliceIterMut<T> {
SliceIterMut {
slice_start: self.ptr,
row_pos: 0,
col_pos: 0,
slice_rows: self.rows,
slice_cols: self.cols,
row_stride: self.row_stride,
_marker: PhantomData::<&mut T>,
}
}
}
impl<'a, T: Copy> MatrixSliceMut<'a, T> {
pub fn into_matrix(self) -> Matrix<T> {
self.iter_rows().collect::<Matrix<T>>()
}
}
#[derive(Debug)]
pub struct SliceIter<'a, T: 'a> {
slice_start: *const T,
row_pos: usize,
col_pos: usize,
slice_rows: usize,
slice_cols: usize,
row_stride: usize,
_marker: PhantomData<&'a T>,
}
#[derive(Debug)]
pub struct SliceIterMut<'a, T: 'a> {
slice_start: *mut T,
row_pos: usize,
col_pos: usize,
slice_rows: usize,
slice_cols: usize,
row_stride: usize,
_marker: PhantomData<&'a mut T>,
}
macro_rules! impl_slice_iter (
($slice_iter:ident, $data_type:ty) => (
impl<'a, T> Iterator for $slice_iter<'a, T> {
type Item = $data_type;
fn next(&mut self) -> Option<Self::Item> {
if self.row_pos < self.slice_rows {
unsafe {
let iter_ptr = self.slice_start.offset((
self.row_pos * self.row_stride + self.col_pos)
as isize);
if self.col_pos == self.slice_cols - 1 {
self.row_pos += 1usize;
self.col_pos = 0usize;
} else {
self.col_pos += 1usize;
}
Some(mem::transmute(iter_ptr))
}
} else {
None
}
}
}
);
);
impl_slice_iter!(SliceIter, &'a T);
impl_slice_iter!(SliceIterMut, &'a mut T);
#[cfg(test)]
mod tests {
use super::BaseSlice;
use super::super::MatrixSlice;
use super::super::MatrixSliceMut;
use super::super::Matrix;
#[test]
#[should_panic]
fn make_slice_bad_dim() {
let a = Matrix::new(3, 3, vec![2.0; 9]);
let _ = MatrixSlice::from_matrix(&a, [1, 1], 3, 2);
}
#[test]
fn make_slice() {
let a = Matrix::new(3, 3, vec![2.0; 9]);
let b = MatrixSlice::from_matrix(&a, [1, 1], 2, 2);
assert_eq!(b.rows(), 2);
assert_eq!(b.cols(), 2);
}
#[test]
fn reslice() {
let mut a = Matrix::new(4, 4, (0..16).collect::<Vec<_>>());
{
let b = MatrixSlice::from_matrix(&a, [1, 1], 3, 3);
let c = b.reslice([0, 1], 2, 2);
assert_eq!(c.rows(), 2);
assert_eq!(c.cols(), 2);
assert_eq!(c[[0, 0]], 6);
assert_eq!(c[[0, 1]], 7);
assert_eq!(c[[1, 0]], 10);
assert_eq!(c[[1, 1]], 11);
}
let b = MatrixSliceMut::from_matrix(&mut a, [1, 1], 3, 3);
let c = b.reslice([0, 1], 2, 2);
assert_eq!(c.rows(), 2);
assert_eq!(c.cols(), 2);
assert_eq!(c[[0, 0]], 6);
assert_eq!(c[[0, 1]], 7);
assert_eq!(c[[1, 0]], 10);
assert_eq!(c[[1, 1]], 11);
}
#[test]
fn slice_into_matrix() {
let mut a = Matrix::new(3, 3, vec![2.0; 9]);
{
let b = MatrixSlice::from_matrix(&a, [1, 1], 2, 2);
let c = b.into_matrix();
assert_eq!(c.rows(), 2);
assert_eq!(c.cols(), 2);
}
let d = MatrixSliceMut::from_matrix(&mut a, [1, 1], 2, 2);
let e = d.into_matrix();
assert_eq!(e.rows(), 2);
assert_eq!(e.cols(), 2);
}
}