@@ -203,3 +203,143 @@ impl<A> Array<A, Ix2> {
203203 }
204204}
205205
206+ impl < A , D > Array < A , D >
207+ where D : Dimension
208+ {
209+ /// Append a row to an array with row major memory layout.
210+ ///
211+ /// ***Errors*** with a layout error if the array is not in standard order or
212+ /// if it has holes, even exterior holes (from slicing). <br>
213+ /// ***Errors*** with shape error if the length of the input row does not match
214+ /// the length of the rows in the array. <br>
215+ ///
216+ /// The memory layout matters, since it determines in which direction the array can easily
217+ /// grow. Notice that an empty array is compatible both ways. The amortized average
218+ /// complexity of the append is O(m) where *m* is the length of the row.
219+ ///
220+ /// ```rust
221+ /// use ndarray::{Array, ArrayView, array};
222+ ///
223+ /// // create an empty array and append
224+ /// let mut a = Array::zeros((0, 4));
225+ /// a.try_append_row(ArrayView::from(&[1., 2., 3., 4.])).unwrap();
226+ /// a.try_append_row(ArrayView::from(&[0., -2., -3., -4.])).unwrap();
227+ ///
228+ /// assert_eq!(
229+ /// a,
230+ /// array![[1., 2., 3., 4.],
231+ /// [0., -2., -3., -4.]]);
232+ /// ```
233+ pub fn try_append_array ( & mut self , axis : Axis , array : ArrayView < A , D > )
234+ -> Result < ( ) , ShapeError >
235+ where
236+ A : Clone ,
237+ D : RemoveAxis ,
238+ {
239+ if self . ndim ( ) == 0 {
240+ return Err ( ShapeError :: from_kind ( ErrorKind :: IncompatibleShape ) ) ;
241+ }
242+
243+ let remaining_shape = self . raw_dim ( ) . remove_axis ( axis) ;
244+ let array_rem_shape = array. raw_dim ( ) . remove_axis ( axis) ;
245+
246+ if remaining_shape != array_rem_shape {
247+ return Err ( ShapeError :: from_kind ( ErrorKind :: IncompatibleShape ) ) ;
248+ }
249+
250+ let len_to_append = array. len ( ) ;
251+ if len_to_append == 0 {
252+ return Ok ( ( ) ) ;
253+ }
254+
255+ let array_shape = array. raw_dim ( ) ;
256+ let mut res_dim = self . raw_dim ( ) ;
257+ res_dim[ axis. index ( ) ] += array_shape[ axis. index ( ) ] ;
258+ let new_len = dimension:: size_of_shape_checked ( & res_dim) ?;
259+
260+ let self_is_empty = self . is_empty ( ) ;
261+
262+ // array must be empty or have `axis` as the outermost (longest stride)
263+ // axis
264+ if !( self_is_empty ||
265+ self . axes ( ) . max_by_key ( |ax| ax. stride ) . map ( |ax| ax. axis ) == Some ( axis) )
266+ {
267+ return Err ( ShapeError :: from_kind ( ErrorKind :: IncompatibleLayout ) ) ;
268+ }
269+
270+ // array must be be "full" (have no exterior holes)
271+ if self . len ( ) != self . data . len ( ) {
272+ return Err ( ShapeError :: from_kind ( ErrorKind :: IncompatibleLayout ) ) ;
273+ }
274+ let strides = if self_is_empty {
275+ // recompute strides - if the array was previously empty, it could have
276+ // zeros in strides.
277+ res_dim. default_strides ( )
278+ } else {
279+ self . strides . clone ( )
280+ } ;
281+
282+ unsafe {
283+ // grow backing storage and update head ptr
284+ debug_assert_eq ! ( self . data. as_ptr( ) , self . as_ptr( ) ) ;
285+ self . ptr = self . data . reserve ( len_to_append) ; // because we are standard order
286+
287+ // copy elements from view to the array now
288+ //
289+ // make a raw view with the new row
290+ // safe because the data was "full"
291+ let tail_ptr = self . data . as_end_nonnull ( ) ;
292+ let tail_view = RawArrayViewMut :: new ( tail_ptr, array_shape, strides. clone ( ) ) ;
293+
294+ struct SetLenOnDrop < ' a , A : ' a > {
295+ len : usize ,
296+ data : & ' a mut OwnedRepr < A > ,
297+ }
298+
299+ let mut length_guard = SetLenOnDrop {
300+ len : self . data . len ( ) ,
301+ data : & mut self . data ,
302+ } ;
303+
304+ impl < A > Drop for SetLenOnDrop < ' _ , A > {
305+ fn drop ( & mut self ) {
306+ unsafe {
307+ self . data . set_len ( self . len ) ;
308+ }
309+ }
310+ }
311+
312+ // we have a problem here XXX
313+ //
314+ // To be robust for panics and drop the right elements, we want
315+ // to fill the tail in-order, so that we can drop the right elements on
316+ // panic. Don't know how to achieve that.
317+ //
318+ // It might be easier to retrace our steps in a scope guard to drop the right
319+ // elements.. (PartialArray style).
320+ //
321+ // assign the new elements
322+ Zip :: from ( tail_view) . and ( array)
323+ . for_each ( |to, from| {
324+ to. write ( from. clone ( ) ) ;
325+ length_guard. len += 1 ;
326+ } ) ;
327+
328+ //length_guard.len += len_to_append;
329+ dbg ! ( len_to_append) ;
330+ drop ( length_guard) ;
331+
332+ // update array dimension
333+ self . strides = strides;
334+ self . dim = res_dim;
335+ dbg ! ( & self . dim) ;
336+
337+ }
338+ // multiple assertions after pointer & dimension update
339+ debug_assert_eq ! ( self . data. len( ) , self . len( ) ) ;
340+ debug_assert_eq ! ( self . len( ) , new_len) ;
341+ debug_assert ! ( self . is_standard_layout( ) ) ;
342+
343+ Ok ( ( ) )
344+ }
345+ }
0 commit comments