From d4ea5f61cf2c04d2ae631ab7ccfde6c2358dab5a Mon Sep 17 00:00:00 2001 From: Johann Tuffe Date: Wed, 27 Jul 2016 05:27:22 +0800 Subject: [PATCH] implement get_row_* for Matrix, MatrixSlice and MatrixSliceMut (#8) * 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 --- src/matrix/mod.rs | 81 +++++++++++++++++++++++++++++++++++ src/matrix/slice.rs | 102 ++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 174 insertions(+), 9 deletions(-) diff --git a/src/matrix/mod.rs b/src/matrix/mod.rs index 4a8806e..d773f29 100644 --- a/src/matrix/mod.rs +++ b/src/matrix/mod.rs @@ -269,6 +269,87 @@ impl Matrix { 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 Clone for Matrix { diff --git a/src/matrix/slice.rs b/src/matrix/slice.rs index 0d35cc2..564f327 100644 --- a/src/matrix/slice.rs +++ b/src/matrix/slice.rs @@ -39,7 +39,53 @@ pub trait BaseSlice { 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::>()); + /// 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::>()); + /// 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 for MatrixSlice<'a, T> { @@ -58,10 +104,6 @@ impl<'a, T> BaseSlice 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 for MatrixSliceMut<'a, T> { @@ -80,10 +122,6 @@ impl<'a, T> BaseSlice 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> { @@ -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::>()); + /// 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::>()); + /// 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> {