diff --git a/src/core/construction.rs b/src/core/construction.rs index 48c055a0..ae536be4 100644 --- a/src/core/construction.rs +++ b/src/core/construction.rs @@ -586,7 +586,7 @@ where N: Scalar + Zero + One, #[inline] pub fn x() -> Self where R::Value: Cmp { - let mut res = Self::from_element(N::zero()); + let mut res = Self::zeros(); unsafe { *res.vget_unchecked_mut(0) = N::one(); } res @@ -596,7 +596,7 @@ where N: Scalar + Zero + One, #[inline] pub fn y() -> Self where R::Value: Cmp { - let mut res = Self::from_element(N::zero()); + let mut res = Self::zeros(); unsafe { *res.vget_unchecked_mut(1) = N::one(); } res @@ -606,7 +606,7 @@ where N: Scalar + Zero + One, #[inline] pub fn z() -> Self where R::Value: Cmp { - let mut res = Self::from_element(N::zero()); + let mut res = Self::zeros(); unsafe { *res.vget_unchecked_mut(2) = N::one(); } res @@ -616,7 +616,7 @@ where N: Scalar + Zero + One, #[inline] pub fn w() -> Self where R::Value: Cmp { - let mut res = Self::from_element(N::zero()); + let mut res = Self::zeros(); unsafe { *res.vget_unchecked_mut(3) = N::one(); } res @@ -626,7 +626,7 @@ where N: Scalar + Zero + One, #[inline] pub fn a() -> Self where R::Value: Cmp { - let mut res = Self::from_element(N::zero()); + let mut res = Self::zeros(); unsafe { *res.vget_unchecked_mut(4) = N::one(); } res @@ -636,7 +636,7 @@ where N: Scalar + Zero + One, #[inline] pub fn b() -> Self where R::Value: Cmp { - let mut res = Self::from_element(N::zero()); + let mut res = Self::zeros(); unsafe { *res.vget_unchecked_mut(5) = N::one(); } res diff --git a/src/core/edition.rs b/src/core/edition.rs index 23106484..baf33d54 100644 --- a/src/core/edition.rs +++ b/src/core/edition.rs @@ -438,21 +438,30 @@ impl> Matrix { * */ + /// Resizes this matrix so that it contains `new_nrows` rows and `new_ncols` columns. + /// + /// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more + /// rows and/or columns than `self`, then the extra rows or columns are filled with `val`. pub fn resize(self, new_nrows: usize, new_ncols: usize, val: N) -> DMatrix where DefaultAllocator: Reallocator { self.resize_generic(Dynamic::new(new_nrows), Dynamic::new(new_ncols), val) } + /// Resizes this matrix so that it contains `R2::value()` rows and `C2::value()` columns. + /// + /// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more + /// rows and/or columns than `self`, then the extra rows or columns are filled with `val`. pub fn fixed_resize(self, val: N) -> MatrixMN where DefaultAllocator: Reallocator { self.resize_generic(R2::name(), C2::name(), val) } - /// Resizes `self` such that it has dimensions `new_nrows × now_ncols`. The values are copied - /// such that `self[(i, j)] == result[(i, j)]`. If the result has more rows and/or columns than - /// `self`, then the extra rows or columns are filled with `val`. + /// Resizes `self` such that it has dimensions `new_nrows × now_ncols`. + /// + /// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more + /// rows and/or columns than `self`, then the extra rows or columns are filled with `val`. #[inline] pub fn resize_generic(self, new_nrows: R2, new_ncols: C2, val: N) -> MatrixMN where DefaultAllocator: Reallocator { diff --git a/src/core/matrix_slice.rs b/src/core/matrix_slice.rs index 4fa518d9..71b2ea99 100644 --- a/src/core/matrix_slice.rs +++ b/src/core/matrix_slice.rs @@ -193,11 +193,12 @@ impl> Matrix { #[inline] fn assert_slice_index(&self, start: (usize, usize), shape: (usize, usize), steps: (usize, usize)) { let my_shape = self.shape(); - // NOTE: we previously did: (shape.0 - 1) * steps.0 - // which was wrong because underflow may occur for zero-sized matrices. - // Istead, we moved the subtraction into an addition on the right hand side. - assert!(start.0 + shape.0 * steps.0 <= my_shape.0 + steps.0, "Matrix slicing out of bounds."); - assert!(start.1 + shape.1 * steps.1 <= my_shape.1 + steps.1, "Matrix slicing out of bounds."); + // NOTE: we don't do any subtraction to avoid underflow for zero-sized matrices. + // + // Terms that would have been negative are moved to the other side of the inequality + // instead. + assert!(start.0 + (steps.0 + 1) * shape.0 <= my_shape.0 + steps.0, "Matrix slicing out of bounds."); + assert!(start.1 + (steps.1 + 1) * shape.1 <= my_shape.1 + steps.1, "Matrix slicing out of bounds."); } } @@ -290,7 +291,7 @@ macro_rules! matrix_slice_impl( -> $MatrixSlice { let my_shape = $me.data.shape(); - $me.assert_slice_index((row_start, 0), (nrows.value(), my_shape.1.value()), (1, 1)); + $me.assert_slice_index((row_start, 0), (nrows.value(), my_shape.1.value()), (0, 0)); let shape = (nrows, my_shape.1); @@ -309,7 +310,7 @@ macro_rules! matrix_slice_impl( let my_shape = $me.data.shape(); let my_strides = $me.data.strides(); - $me.assert_slice_index((row_start, 0), (nrows.value(), my_shape.1.value()), (step, 1)); + $me.assert_slice_index((row_start, 0), (nrows.value(), my_shape.1.value()), (step, 0)); let strides = (Dynamic::new((step + 1) * my_strides.0.value()), my_strides.1); let shape = (nrows, my_shape.1); @@ -378,7 +379,7 @@ macro_rules! matrix_slice_impl( -> $MatrixSlice { let my_shape = $me.data.shape(); - $me.assert_slice_index((0, first_col), (my_shape.0.value(), ncols.value()), (1, 1)); + $me.assert_slice_index((0, first_col), (my_shape.0.value(), ncols.value()), (0, 0)); let shape = (my_shape.0, ncols); unsafe { @@ -397,7 +398,7 @@ macro_rules! matrix_slice_impl( let my_shape = $me.data.shape(); let my_strides = $me.data.strides(); - $me.assert_slice_index((0, first_col), (my_shape.0.value(), ncols.value()), (1, step)); + $me.assert_slice_index((0, first_col), (my_shape.0.value(), ncols.value()), (0, step)); let strides = (my_strides.0, Dynamic::new((step + 1) * my_strides.1.value())); let shape = (my_shape.0, ncols); @@ -419,7 +420,7 @@ macro_rules! matrix_slice_impl( pub fn $slice($me: $Me, start: (usize, usize), shape: (usize, usize)) -> $MatrixSlice { - $me.assert_slice_index(start, shape, (1, 1)); + $me.assert_slice_index(start, shape, (0, 0)); let shape = (Dynamic::new(shape.0), Dynamic::new(shape.1)); unsafe { @@ -449,7 +450,7 @@ macro_rules! matrix_slice_impl( where RSlice: DimName, CSlice: DimName { - $me.assert_slice_index((irow, icol), (RSlice::dim(), CSlice::dim()), (1, 1)); + $me.assert_slice_index((irow, icol), (RSlice::dim(), CSlice::dim()), (0, 0)); let shape = (RSlice::name(), CSlice::name()); unsafe { @@ -478,7 +479,7 @@ macro_rules! matrix_slice_impl( where RSlice: Dim, CSlice: Dim { - $me.assert_slice_index(start, (shape.0.value(), shape.1.value()), (1, 1)); + $me.assert_slice_index(start, (shape.0.value(), shape.1.value()), (0, 0)); unsafe { let data = $SliceStorage::new_unchecked($data, start, shape); @@ -644,12 +645,23 @@ matrix_slice_impl!( columns_range_pair_mut); +/// A range with a size that may be known at compile-time. +/// +/// This may be: +/// * A single `usize` index, e.g., `4` +/// * A left-open range `std::ops::RangeTo`, e.g., `.. 4` +/// * A right-open range `std::ops::RangeFrom`, e.g., `4 ..` +/// * A full range `std::ops::RangeFull`, e.g., `..` pub trait SliceRange { + /// Type of the range size. May be a type-level integer. type Size: Dim; + /// The start index of the range. fn begin(&self, shape: D) -> usize; // NOTE: this is the index immediatly after the last index. + /// The index immediatly after the last index inside of the range. fn end(&self, shape: D) -> usize; + /// The number of elements of the range, i.e., `self.end - self.begin`. fn size(&self, shape: D) -> Self::Size; } @@ -750,6 +762,8 @@ impl SliceRange for RangeFull { impl> Matrix { + /// Slices a sub-matrix containing the rows indexed by the range `rows` and the columns indexed + /// by the range `cols`. #[inline] pub fn slice_range(&self, rows: RowRange, cols: ColRange) -> MatrixSlice @@ -761,6 +775,7 @@ impl> Matrix { (rows.size(nrows), cols.size(ncols))) } + /// Slice containing all the rows indexed by the range `rows`. #[inline] pub fn rows_range>(&self, rows: RowRange) -> MatrixSlice { @@ -768,6 +783,7 @@ impl> Matrix { self.slice_range(rows, ..) } + /// Slice containing all the columns indexed by the range `rows`. #[inline] pub fn columns_range>(&self, cols: ColRange) -> MatrixSlice { @@ -777,6 +793,8 @@ impl> Matrix { } impl> Matrix { + /// Slices a mutable sub-matrix containing the rows indexed by the range `rows` and the columns + /// indexed by the range `cols`. pub fn slice_range_mut(&mut self, rows: RowRange, cols: ColRange) -> MatrixSliceMut where RowRange: SliceRange, @@ -787,6 +805,7 @@ impl> Matrix { (rows.size(nrows), cols.size(ncols))) } + /// Slice containing all the rows indexed by the range `rows`. #[inline] pub fn rows_range_mut>(&mut self, rows: RowRange) -> MatrixSliceMut { @@ -794,6 +813,7 @@ impl> Matrix { self.slice_range_mut(rows, ..) } + /// Slice containing all the columns indexed by the range `cols`. #[inline] pub fn columns_range_mut>(&mut self, cols: ColRange) -> MatrixSliceMut { diff --git a/src/core/scalar.rs b/src/core/scalar.rs index 29e2c76d..6735523b 100644 --- a/src/core/scalar.rs +++ b/src/core/scalar.rs @@ -7,6 +7,9 @@ use std::any::Any; /// This does not make any assumption on the algebraic properties of `Self`. pub trait Scalar: Copy + PartialEq + Debug + Any { #[inline] + /// Tests if `Self` the the same as the type `T` + /// + /// Typically used to test of `Self` is a f32 or a f64 with `N::is::()`. fn is() -> bool { TypeId::of::() == TypeId::of::() } diff --git a/src/lib.rs b/src/lib.rs index c1c47673..8b1ee29b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,7 +15,7 @@ Simply add the following to your `Cargo.toml` file: ```.ignore [dependencies] -nalgebra = "0.12" +nalgebra = "0.13" ``` @@ -84,7 +84,7 @@ an optimized set of tools for computer graphics and physics. Those features incl #![deny(non_upper_case_globals)] #![deny(unused_qualifications)] #![deny(unused_results)] -//#![warn(missing_docs)] +#![deny(missing_docs)] #![doc(html_root_url = "http://nalgebra.org/rustdoc")] #[cfg(feature = "arbitrary")] diff --git a/tests/core/matrix_slice.rs b/tests/core/matrix_slice.rs index 9313a3db..70e88cf9 100644 --- a/tests/core/matrix_slice.rs +++ b/tests/core/matrix_slice.rs @@ -189,3 +189,59 @@ fn columns_range_pair() { 32.0, 33.0, 34.0); assert!(l.eq(&expected_l) && r.eq(&expected_r)); } + +#[test] +#[should_panic] +fn row_out_of_bounds() { + let a = Matrix3x4::::zeros(); + a.row(3); +} + +#[test] +#[should_panic] +fn rows_out_of_bounds() { + let a = Matrix3x4::::zeros(); + a.rows(1, 3); +} + +#[test] +#[should_panic] +fn rows_with_step_out_of_bounds() { + let a = Matrix3x4::::zeros(); + a.rows_with_step(1, 2, 1); +} + +#[test] +#[should_panic] +fn column_out_of_bounds() { + let a = Matrix3x4::::zeros(); + a.column(4); +} + +#[test] +#[should_panic] +fn columns_out_of_bounds() { + let a = Matrix3x4::::zeros(); + a.columns(2, 3); +} + +#[test] +#[should_panic] +fn columns_with_step_out_of_bounds() { + let a = Matrix3x4::::zeros(); + a.columns_with_step(2, 2, 1); +} + +#[test] +#[should_panic] +fn slice_out_of_bounds() { + let a = Matrix3x4::::zeros(); + a.slice((1, 2), (3, 1)); +} + +#[test] +#[should_panic] +fn slice_with_steps_out_of_bounds() { + let a = Matrix3x4::::zeros(); + a.slice_with_steps((1, 2), (2, 2), (0, 1)); +}