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