Skip to content

Commit 6933dd8

Browse files
ssande7bluss
authored andcommitted
Add reserve method for owned arrays
1 parent a4764ef commit 6933dd8

2 files changed

Lines changed: 93 additions & 7 deletions

File tree

src/impl_owned_array.rs

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -660,14 +660,10 @@ where D: Dimension
660660
self.strides.clone()
661661
};
662662

663-
unsafe {
664-
// grow backing storage and update head ptr
665-
let offset_from_alloc_to_logical = self.offset_from_alloc_to_logical_ptr().unwrap_or(0);
666-
self.ptr = self
667-
.data
668-
.reserve(len_to_append)
669-
.add(offset_from_alloc_to_logical);
663+
// grow backing storage and update head ptr
664+
self.reserve(axis, array_dim[axis.index()]);
670665

666+
unsafe {
671667
// clone elements from view to the array now
672668
//
673669
// To be robust for panics and drop the right elements, we want
@@ -751,6 +747,44 @@ where D: Dimension
751747

752748
Ok(())
753749
}
750+
751+
/// Reserve capacity to grow array along `axis` by at least `additional` elements.
752+
///
753+
/// Existing elements of `array` are untouched and the backing storage is grown by
754+
/// calling the underlying `reserve` method of the `OwnedRepr`.
755+
///
756+
/// This is useful when pushing or appending repeatedly to an array to avoid multiple
757+
/// allocations.
758+
///
759+
/// ```rust
760+
/// use ndarray::{Array3, Axis};
761+
/// let mut a = Array3::<i32>::zeros((0,2,4));
762+
/// a.reserve(Axis(0), 1000);
763+
/// assert!(a.into_raw_vec().capacity() >= 2*4*1000);
764+
pub fn reserve(&mut self, axis: Axis, additional: usize)
765+
where D: RemoveAxis
766+
{
767+
if additional == 0 {
768+
return;
769+
}
770+
let self_dim = self.raw_dim();
771+
let remaining_shape = self_dim.remove_axis(axis);
772+
let len_to_append = remaining_shape.size() * additional;
773+
774+
unsafe {
775+
// grow backing storage and update head ptr
776+
let data_to_array_offset = if std::mem::size_of::<A>() != 0 {
777+
self.as_ptr().offset_from(self.data.as_ptr())
778+
} else {
779+
0
780+
};
781+
debug_assert!(data_to_array_offset >= 0);
782+
self.ptr = self
783+
.data
784+
.reserve(len_to_append)
785+
.offset(data_to_array_offset);
786+
}
787+
}
754788
}
755789

756790
/// This drops all "unreachable" elements in `self_` given the data pointer and data length.

tests/reserve.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
use ndarray::prelude::*;
2+
3+
#[test]
4+
fn reserve_1d()
5+
{
6+
let mut a = Array1::<i32>::zeros((4,));
7+
a.reserve(Axis(0), 1000);
8+
assert_eq!(a.shape(), &[4]);
9+
assert!(a.into_raw_vec().capacity() >= 1004);
10+
}
11+
12+
#[test]
13+
fn reserve_3d()
14+
{
15+
let mut a = Array3::<i32>::zeros((0, 4, 8));
16+
a.reserve(Axis(0), 10);
17+
assert_eq!(a.shape(), &[0, 4, 8]);
18+
assert!(a.into_raw_vec().capacity() >= 4 * 8 * 10);
19+
}
20+
21+
#[test]
22+
fn reserve_empty_3d()
23+
{
24+
let mut a = Array3::<i32>::zeros((0, 0, 0));
25+
a.reserve(Axis(0), 10);
26+
}
27+
28+
#[test]
29+
fn reserve_3d_axis1()
30+
{
31+
let mut a = Array3::<i32>::zeros((2, 4, 8));
32+
a.reserve(Axis(1), 10);
33+
assert!(a.into_raw_vec().capacity() >= 2 * 8 * 10);
34+
}
35+
36+
#[test]
37+
fn reserve_3d_repeat()
38+
{
39+
let mut a = Array3::<i32>::zeros((2, 4, 8));
40+
a.reserve(Axis(1), 10);
41+
a.reserve(Axis(2), 30);
42+
assert!(a.into_raw_vec().capacity() >= 2 * 4 * 30);
43+
}
44+
45+
#[test]
46+
fn reserve_2d_with_data()
47+
{
48+
let mut a = array![[1, 2], [3, 4], [5, 6]];
49+
a.reserve(Axis(1), 100);
50+
assert_eq!(a, array![[1, 2], [3, 4], [5, 6]]);
51+
assert!(a.into_raw_vec().capacity() >= 3 * 100);
52+
}

0 commit comments

Comments
 (0)