@@ -251,6 +251,52 @@ impl<A> Array<A, Ix2>
251251 {
252252 self . append ( Axis ( 1 ) , column. insert_axis ( Axis ( 1 ) ) )
253253 }
254+
255+ /// Reserve capacity to grow array by at least `additional` rows.
256+ ///
257+ /// Existing elements of `array` are untouched and the backing storage is grown by
258+ /// calling the underlying `reserve` method of the `OwnedRepr`.
259+ ///
260+ /// This is useful when pushing or appending repeatedly to an array to avoid multiple
261+ /// allocations.
262+ ///
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+ ///
267+ /// ```rust
268+ /// use ndarray::Array2;
269+ /// let mut a = Array2::<i32>::zeros((2,4));
270+ /// a.reserve_rows(1000).unwrap();
271+ /// assert!(a.into_raw_vec().capacity() >= 4*1002);
272+ /// ```
273+ pub fn reserve_rows ( & mut self , additional : usize ) -> Result < ( ) , ShapeError >
274+ {
275+ self . reserve ( Axis ( 0 ) , additional)
276+ }
277+
278+ /// Reserve capacity to grow array by at least `additional` columns.
279+ ///
280+ /// Existing elements of `array` are untouched and the backing storage is grown by
281+ /// calling the underlying `reserve` method of the `OwnedRepr`.
282+ ///
283+ /// This is useful when pushing or appending repeatedly to an array to avoid multiple
284+ /// allocations.
285+ ///
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+ ///
290+ /// ```rust
291+ /// use ndarray::Array2;
292+ /// let mut a = Array2::<i32>::zeros((2,4));
293+ /// a.reserve_columns(1000).unwrap();
294+ /// assert!(a.into_raw_vec().capacity() >= 2*1002);
295+ /// ```
296+ pub fn reserve_columns ( & mut self , additional : usize ) -> Result < ( ) , ShapeError >
297+ {
298+ self . reserve ( Axis ( 1 ) , additional)
299+ }
254300}
255301
256302impl < A , D > Array < A , D >
@@ -660,14 +706,10 @@ where D: Dimension
660706 self . strides . clone ( )
661707 } ;
662708
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) ;
709+ // grow backing storage and update head ptr
710+ self . reserve ( axis, array_dim[ axis. index ( ) ] ) ?;
670711
712+ unsafe {
671713 // clone elements from view to the array now
672714 //
673715 // To be robust for panics and drop the right elements, we want
@@ -751,6 +793,70 @@ where D: Dimension
751793
752794 Ok ( ( ) )
753795 }
796+
797+ /// Reserve capacity to grow array along `axis` by at least `additional` elements.
798+ ///
799+ /// The axis should be in the range `Axis(` 0 .. *n* `)` where *n* is the
800+ /// number of dimensions (axes) of the array.
801+ ///
802+ /// Existing elements of `array` are untouched and the backing storage is grown by
803+ /// calling the underlying `reserve` method of the `OwnedRepr`.
804+ ///
805+ /// This is useful when pushing or appending repeatedly to an array to avoid multiple
806+ /// allocations.
807+ ///
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+ ///
814+ /// ```rust
815+ /// use ndarray::{Array3, Axis};
816+ /// let mut a = Array3::<i32>::zeros((0,2,4));
817+ /// a.reserve(Axis(0), 1000).unwrap();
818+ /// assert!(a.into_raw_vec().capacity() >= 2*4*1000);
819+ /// ```
820+ ///
821+ pub fn reserve ( & mut self , axis : Axis , additional : usize ) -> Result < ( ) , ShapeError >
822+ where D : RemoveAxis
823+ {
824+ debug_assert ! ( axis. index( ) < self . ndim( ) ) ;
825+ let self_dim = self . raw_dim ( ) ;
826+ let remaining_shape = self_dim. remove_axis ( axis) ;
827+
828+ // Make sure added capacity doesn't overflow usize::MAX
829+ let len_to_append = remaining_shape
830+ . size ( )
831+ . checked_mul ( additional)
832+ . ok_or ( ShapeError :: from_kind ( ErrorKind :: Overflow ) ) ?;
833+
834+ // Make sure new capacity is still in bounds
835+ let mut res_dim = self_dim;
836+ res_dim[ axis. index ( ) ] += additional;
837+ let new_len = dimension:: size_of_shape_checked ( & res_dim) ?;
838+
839+ // Check whether len_to_append would cause an overflow
840+ debug_assert_eq ! ( self . len( ) . checked_add( len_to_append) . unwrap( ) , new_len) ;
841+
842+ unsafe {
843+ // grow backing storage and update head ptr
844+ let data_to_array_offset = if std:: mem:: size_of :: < A > ( ) != 0 {
845+ self . as_ptr ( ) . offset_from ( self . data . as_ptr ( ) )
846+ } else {
847+ 0
848+ } ;
849+ debug_assert ! ( data_to_array_offset >= 0 ) ;
850+ self . ptr = self
851+ . data
852+ . reserve ( len_to_append)
853+ . offset ( data_to_array_offset) ;
854+ }
855+
856+ debug_assert ! ( self . pointer_is_inbounds( ) ) ;
857+
858+ Ok ( ( ) )
859+ }
754860}
755861
756862/// This drops all "unreachable" elements in `self_` given the data pointer and data length.
0 commit comments