Skip to content

Commit

Permalink
implement get_row_* for Matrix, MatrixSlice and MatrixSliceMut (#8)
Browse files Browse the repository at this point in the history
* implement get_row_* for Matrix, MatrixSlice and MatrixSliceMut

- get_row
- get_row_mut
- get_row_unchecked
- get_row_mut_unchecked

Note:
For MatrixSlices, get_row and get_row_unchecked are implemented
directly on BaseSlice trait, as it already provides all necessary methods.

Similarly, moved get_unchecked slice implementations directly into the
trait

* rename get_row_mut_unchecked into get_row_unchecked_mut

To follow std::slice syntax

* use if/else instead of return
  • Loading branch information
tafia authored and AtheMathmo committed Jul 26, 2016
1 parent 4fc41c6 commit d4ea5f6
Show file tree
Hide file tree
Showing 2 changed files with 174 additions and 9 deletions.
81 changes: 81 additions & 0 deletions src/matrix/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,87 @@ impl<T> Matrix<T> {
let cols = self.cols;
MatrixSliceMut::from_matrix(self, [0, 0], rows, cols)
}

/// Returns the row of a `Matrix` at the given index.
/// `None` if the index is out of bounds.
///
/// # Examples
///
/// ```
/// use rulinalg::matrix::Matrix;
///
/// let a = Matrix::new(3, 4, vec![2.0; 12]);
/// let row = a.get_row(1);
/// let expected = vec![2.0; 4];
/// assert_eq!(row, Some(&*expected));
/// assert!(a.get_row(5).is_none());
/// ```
pub fn get_row(&self, index: usize) -> Option<&[T]> {
if index < self.rows {
unsafe { Some(self.get_row_unchecked(index)) }
} else {
None
}
}

/// Returns the row of a `Matrix` at the given index without doing unbounds checking
///
/// # Examples
///
/// ```
/// use rulinalg::matrix::Matrix;
///
/// let a = Matrix::new(3, 4, vec![2.0; 12]);
/// let row = unsafe { a.get_row_unchecked(1) };
/// let expected = vec![2.0; 4];
/// assert_eq!(row, &*expected);
/// ```
pub unsafe fn get_row_unchecked(&self, index: usize) -> &[T] {
let ptr = self.data.as_ptr().offset((self.cols * index) as isize);
::std::slice::from_raw_parts(ptr, self.cols)
}

/// Returns a mutable reference to the row of a `Matrix` at the given index.
/// `None` if the index is out of bounds.
///
/// # Examples
///
/// ```
/// use rulinalg::matrix::Matrix;
///
/// let mut a = Matrix::new(3, 4, vec![2.0; 12]);
/// {
/// let row = a.get_row_mut(1);
/// let mut expected = vec![2.0; 4];
/// assert_eq!(row, Some(&mut *expected));
/// }
/// assert!(a.get_row_mut(5).is_none());
/// ```
pub fn get_row_mut(&mut self, index: usize) -> Option<&mut [T]> {
if index < self.rows {
unsafe { Some(self.get_row_unchecked_mut(index)) }
} else {
None
}
}

/// Returns a mutable reference to the row of a `Matrix` at the given index
/// without doing unbounds checking
///
/// # Examples
///
/// ```
/// use rulinalg::matrix::Matrix;
///
/// let mut a = Matrix::new(3, 4, vec![2.0; 12]);
/// let row = unsafe { a.get_row_unchecked_mut(1) };
/// let mut expected = vec![2.0; 4];
/// assert_eq!(row, &mut *expected);
/// ```
pub unsafe fn get_row_unchecked_mut(&mut self, index: usize) -> &mut [T] {
let ptr = self.data.as_mut_ptr().offset((self.cols * index) as isize);
::std::slice::from_raw_parts_mut(ptr, self.cols)
}
}

impl<T: Clone> Clone for Matrix<T> {
Expand Down
102 changes: 93 additions & 9 deletions src/matrix/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,53 @@ pub trait BaseSlice<T> {
fn as_ptr(&self) -> *const T;

/// Get a reference to a point in the slice without bounds checking.
unsafe fn get_unchecked(&self, index: [usize; 2]) -> &T;
unsafe fn get_unchecked(&self, index: [usize; 2]) -> &T {
&*(self.as_ptr().offset((index[0] * self.row_stride() + index[1]) as isize))
}

/// Returns the row of a `Matrix` at the given index.
/// `None` if the index is out of bounds.
///
/// # Examples
///
/// ```
/// use rulinalg::matrix::{Matrix, MatrixSlice};
/// use rulinalg::matrix::slice::BaseSlice;
///
/// let mut a = Matrix::new(3,3, (0..9).collect::<Vec<usize>>());
/// let mut slice = MatrixSlice::from_matrix(&mut a, [1,1], 2, 2);
/// let row = slice.get_row(1);
/// let mut expected = vec![7usize, 8];
/// assert_eq!(row, Some(&*expected));
/// assert!(slice.get_row(5).is_none());
/// ```
fn get_row(&self, index: usize) -> Option<&[T]> {
if index < self.rows() {
unsafe { Some(self.get_row_unchecked(index)) }
} else {
None
}
}

/// Returns the row of a `BaseSlice` at the given index without doing unbounds checking
///
/// # Examples
///
/// ```
/// use rulinalg::matrix::{Matrix, MatrixSlice};
/// use rulinalg::matrix::slice::BaseSlice;
///
/// let mut a = Matrix::new(3,3, (0..9).collect::<Vec<usize>>());
/// let mut slice = MatrixSlice::from_matrix(&mut a, [1,1], 2, 2);
/// let row = unsafe { slice.get_row_unchecked(1) };
/// let mut expected = vec![7usize, 8];
/// assert_eq!(row, &*expected);
/// ```
unsafe fn get_row_unchecked(&self, index: usize) -> &[T] {
let ptr = self.as_ptr().offset((self.row_stride() * index) as isize);
::std::slice::from_raw_parts(ptr, self.cols())
}

}

impl<'a, T> BaseSlice<T> for MatrixSlice<'a, T> {
Expand All @@ -58,10 +104,6 @@ impl<'a, T> BaseSlice<T> for MatrixSlice<'a, T> {
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> {
Expand All @@ -80,10 +122,6 @@ impl<'a, T> BaseSlice<T> for MatrixSliceMut<'a, T> {
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> {
Expand Down Expand Up @@ -375,6 +413,52 @@ impl<'a, T> MatrixSliceMut<'a, T> {
_marker: PhantomData::<&mut T>,
}
}

/// Returns a mutable reference to the row of a `MatrixSliceMut` at the given index.
/// `None` if the index is out of bounds.
///
/// # Examples
///
/// ```
/// use rulinalg::matrix::Matrix;
/// use rulinalg::matrix::MatrixSliceMut;
///
/// let mut a = Matrix::new(3,3, (0..9).collect::<Vec<usize>>());
/// let mut slice = MatrixSliceMut::from_matrix(&mut a, [1,1], 2, 2);
/// {
/// let row = slice.get_row_mut(1);
/// let mut expected = vec![7usize, 8];
/// assert_eq!(row, Some(&mut *expected));
/// }
/// assert!(slice.get_row_mut(5).is_none());
/// ```
pub fn get_row_mut(&mut self, index: usize) -> Option<&mut [T]> {
if index < self.rows {
unsafe { Some(self.get_row_unchecked_mut(index)) }
} else {
None
}
}

/// Returns a mutable reference to the row of a `MatrixSliceMut` at the given index
/// without doing unbounds checking
///
/// # Examples
///
/// ```
/// use rulinalg::matrix::Matrix;
/// use rulinalg::matrix::MatrixSliceMut;
///
/// let mut a = Matrix::new(3,3, (0..9).collect::<Vec<usize>>());
/// let mut slice = MatrixSliceMut::from_matrix(&mut a, [1,1], 2, 2);
/// let row = unsafe { slice.get_row_unchecked_mut(1) };
/// let mut expected = vec![7usize, 8];
/// assert_eq!(row, &mut *expected);
/// ```
pub unsafe fn get_row_unchecked_mut(&mut self, index: usize) -> &mut [T] {
let ptr = self.ptr.offset((self.row_stride * index) as isize);
::std::slice::from_raw_parts_mut(ptr, self.cols)
}
}

impl<'a, T: Copy> MatrixSliceMut<'a, T> {
Expand Down

0 comments on commit d4ea5f6

Please sign in to comment.