Skip to content

Commit a16707a

Browse files
ssande7bluss
authored andcommitted
Add bounds checking and error documentation
1 parent 63062d3 commit a16707a

3 files changed

Lines changed: 46 additions & 17 deletions

File tree

benches/reserve.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ fn push_reserve(bench: &mut Bencher)
1111
let ones: Array<f32, _> = array![1f32];
1212
bench.iter(|| {
1313
let mut a: Array<f32, Ix1> = array![];
14-
a.reserve(Axis(0), 100);
14+
a.reserve(Axis(0), 100).unwrap();
1515
for _ in 0..100 {
1616
a.append(Axis(0), ones.view()).unwrap();
1717
}

src/impl_owned_array.rs

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -260,15 +260,19 @@ impl<A> Array<A, Ix2>
260260
/// This is useful when pushing or appending repeatedly to an array to avoid multiple
261261
/// allocations.
262262
///
263+
/// ***Errors*** with a shape error if the resultant capacity is larger than the addressable
264+
/// bounds; that is, the product of non-zero axis lengths once `axis` has been extended by
265+
/// `additional` exceeds `isize::MAX`.
266+
///
263267
/// ```rust
264268
/// use ndarray::Array2;
265269
/// let mut a = Array2::<i32>::zeros((2,4));
266-
/// a.reserve_rows(1000);
270+
/// a.reserve_rows(1000).unwrap();
267271
/// assert!(a.into_raw_vec().capacity() >= 4*1002);
268272
/// ```
269-
pub fn reserve_rows(&mut self, additional: usize)
273+
pub fn reserve_rows(&mut self, additional: usize) -> Result<(), ShapeError>
270274
{
271-
self.reserve(Axis(0), additional);
275+
self.reserve(Axis(0), additional)
272276
}
273277

274278
/// Reserve capacity to grow array by at least `additional` columns.
@@ -279,15 +283,19 @@ impl<A> Array<A, Ix2>
279283
/// This is useful when pushing or appending repeatedly to an array to avoid multiple
280284
/// allocations.
281285
///
286+
/// ***Errors*** with a shape error if the resultant capacity is larger than the addressable
287+
/// bounds; that is, the product of non-zero axis lengths once `axis` has been extended by
288+
/// `additional` exceeds `isize::MAX`.
289+
///
282290
/// ```rust
283291
/// use ndarray::Array2;
284292
/// let mut a = Array2::<i32>::zeros((2,4));
285-
/// a.reserve_columns(1000);
293+
/// a.reserve_columns(1000).unwrap();
286294
/// assert!(a.into_raw_vec().capacity() >= 2*1002);
287295
/// ```
288-
pub fn reserve_columns(&mut self, additional: usize)
296+
pub fn reserve_columns(&mut self, additional: usize) -> Result<(), ShapeError>
289297
{
290-
self.reserve(Axis(1), additional);
298+
self.reserve(Axis(1), additional)
291299
}
292300
}
293301

@@ -699,7 +707,7 @@ where D: Dimension
699707
};
700708

701709
// grow backing storage and update head ptr
702-
self.reserve(axis, array_dim[axis.index()]);
710+
self.reserve(axis, array_dim[axis.index()])?;
703711

704712
unsafe {
705713
// clone elements from view to the array now
@@ -788,25 +796,42 @@ where D: Dimension
788796

789797
/// Reserve capacity to grow array along `axis` by at least `additional` elements.
790798
///
799+
/// The axis should be in the range `Axis(` 0 .. *n* `)` where *n* is the
800+
/// number of dimensions (axes) of the array.
801+
///
791802
/// Existing elements of `array` are untouched and the backing storage is grown by
792803
/// calling the underlying `reserve` method of the `OwnedRepr`.
793804
///
794805
/// This is useful when pushing or appending repeatedly to an array to avoid multiple
795806
/// allocations.
796807
///
808+
/// ***Panics*** if the axis is out of bounds.
809+
///
810+
/// ***Errors*** with a shape error if the resultant capacity is larger than the addressable
811+
/// bounds; that is, the product of non-zero axis lengths once `axis` has been extended by
812+
/// `additional` exceeds `isize::MAX`.
813+
///
797814
/// ```rust
798815
/// use ndarray::{Array3, Axis};
799816
/// let mut a = Array3::<i32>::zeros((0,2,4));
800-
/// a.reserve(Axis(0), 1000);
817+
/// a.reserve(Axis(0), 1000).unwrap();
801818
/// assert!(a.into_raw_vec().capacity() >= 2*4*1000);
802819
/// ```
803-
pub fn reserve(&mut self, axis: Axis, additional: usize)
820+
///
821+
pub fn reserve(&mut self, axis: Axis, additional: usize) -> Result<(), ShapeError>
804822
where D: RemoveAxis
805823
{
824+
debug_assert!(axis.index() < self.ndim());
806825
let self_dim = self.raw_dim();
807826
let remaining_shape = self_dim.remove_axis(axis);
808827
let len_to_append = remaining_shape.size() * additional;
809828

829+
// Make sure new capacity is still in bounds
830+
let mut res_dim = self_dim;
831+
res_dim[axis.index()] += additional;
832+
let new_len = dimension::size_of_shape_checked(&res_dim)?;
833+
debug_assert_eq!(self.len() + len_to_append, new_len);
834+
810835
unsafe {
811836
// grow backing storage and update head ptr
812837
let data_to_array_offset = if std::mem::size_of::<A>() != 0 {
@@ -820,6 +845,10 @@ where D: Dimension
820845
.reserve(len_to_append)
821846
.offset(data_to_array_offset);
822847
}
848+
849+
debug_assert!(self.pointer_is_inbounds());
850+
851+
Ok(())
823852
}
824853
}
825854

tests/reserve.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use ndarray::prelude::*;
44
fn reserve_1d()
55
{
66
let mut a = Array1::<i32>::zeros((4,));
7-
a.reserve(Axis(0), 1000);
7+
a.reserve(Axis(0), 1000).unwrap();
88
assert_eq!(a.shape(), &[4]);
99
assert!(a.into_raw_vec().capacity() >= 1004);
1010
}
@@ -13,7 +13,7 @@ fn reserve_1d()
1313
fn reserve_3d()
1414
{
1515
let mut a = Array3::<i32>::zeros((0, 4, 8));
16-
a.reserve(Axis(0), 10);
16+
a.reserve(Axis(0), 10).unwrap();
1717
assert_eq!(a.shape(), &[0, 4, 8]);
1818
assert!(a.into_raw_vec().capacity() >= 4 * 8 * 10);
1919
}
@@ -22,31 +22,31 @@ fn reserve_3d()
2222
fn reserve_empty_3d()
2323
{
2424
let mut a = Array3::<i32>::zeros((0, 0, 0));
25-
a.reserve(Axis(0), 10);
25+
a.reserve(Axis(0), 10).unwrap();
2626
}
2727

2828
#[test]
2929
fn reserve_3d_axis1()
3030
{
3131
let mut a = Array3::<i32>::zeros((2, 4, 8));
32-
a.reserve(Axis(1), 10);
32+
a.reserve(Axis(1), 10).unwrap();
3333
assert!(a.into_raw_vec().capacity() >= 2 * 8 * 10);
3434
}
3535

3636
#[test]
3737
fn reserve_3d_repeat()
3838
{
3939
let mut a = Array3::<i32>::zeros((2, 4, 8));
40-
a.reserve(Axis(1), 10);
41-
a.reserve(Axis(2), 30);
40+
a.reserve(Axis(1), 10).unwrap();
41+
a.reserve(Axis(2), 30).unwrap();
4242
assert!(a.into_raw_vec().capacity() >= 2 * 4 * 30);
4343
}
4444

4545
#[test]
4646
fn reserve_2d_with_data()
4747
{
4848
let mut a = array![[1, 2], [3, 4], [5, 6]];
49-
a.reserve(Axis(1), 100);
49+
a.reserve(Axis(1), 100).unwrap();
5050
assert_eq!(a, array![[1, 2], [3, 4], [5, 6]]);
5151
assert!(a.into_raw_vec().capacity() >= 3 * 100);
5252
}

0 commit comments

Comments
 (0)