@@ -258,6 +258,8 @@ impl<A, D> Array<A, D>
258
258
A : Clone ,
259
259
D : RemoveAxis ,
260
260
{
261
+ assert_ne ! ( self . ndim( ) , 0 , "Impossible to append to 0-dim array" ) ;
262
+ let current_axis_len = self . len_of ( axis) ;
261
263
let remaining_shape = self . raw_dim ( ) . remove_axis ( axis) ;
262
264
let array_rem_shape = array. raw_dim ( ) . remove_axis ( axis) ;
263
265
@@ -277,22 +279,46 @@ impl<A, D> Array<A, D>
277
279
278
280
let self_is_empty = self . is_empty ( ) ;
279
281
280
- // array must be empty or have `axis` as the outermost (longest stride)
281
- // axis
282
- if !( self_is_empty ||
283
- self . axes ( ) . max_by_key ( |ax| ax. stride ) . map ( |ax| ax. axis ) == Some ( axis) )
284
- {
285
- return Err ( ShapeError :: from_kind ( ErrorKind :: IncompatibleLayout ) ) ;
282
+ // array must be empty or have `axis` as the outermost (longest stride) axis
283
+ if !self_is_empty && current_axis_len > 1 {
284
+ // `axis` must be max stride axis or equal to its stride
285
+ let max_stride_axis = self . axes ( ) . max_by_key ( |ax| ax. stride ) . unwrap ( ) ;
286
+ if max_stride_axis. axis != axis && max_stride_axis. stride > self . stride_of ( axis) {
287
+ return Err ( ShapeError :: from_kind ( ErrorKind :: IncompatibleLayout ) ) ;
288
+ }
286
289
}
287
290
288
291
// array must be be "full" (have no exterior holes)
289
292
if self . len ( ) != self . data . len ( ) {
290
293
return Err ( ShapeError :: from_kind ( ErrorKind :: IncompatibleLayout ) ) ;
291
294
}
295
+
292
296
let strides = if self_is_empty {
293
- // recompute strides - if the array was previously empty, it could have
294
- // zeros in strides.
295
- res_dim. default_strides ( )
297
+ // recompute strides - if the array was previously empty, it could have zeros in
298
+ // strides.
299
+ // The new order is based on c/f-contig but must have `axis` as outermost axis.
300
+ if axis == Axis ( self . ndim ( ) - 1 ) {
301
+ // prefer f-contig when appending to the last axis
302
+ // Axis n - 1 is outermost axis
303
+ res_dim. fortran_strides ( )
304
+ } else {
305
+ // Default with modification
306
+ res_dim. slice_mut ( ) . swap ( 0 , axis. index ( ) ) ;
307
+ let mut strides = res_dim. default_strides ( ) ;
308
+ res_dim. slice_mut ( ) . swap ( 0 , axis. index ( ) ) ;
309
+ strides. slice_mut ( ) . swap ( 0 , axis. index ( ) ) ;
310
+ strides
311
+ }
312
+ } else if current_axis_len == 1 {
313
+ // This is the outermost/longest stride axis; so we find the max across the other axes
314
+ let new_stride = self . axes ( ) . fold ( 1 , |acc, ax| {
315
+ if ax. axis == axis { acc } else {
316
+ Ord :: max ( acc, ax. len as isize * ax. stride )
317
+ }
318
+ } ) ;
319
+ let mut strides = self . strides . clone ( ) ;
320
+ strides[ axis. index ( ) ] = new_stride as usize ;
321
+ strides
296
322
} else {
297
323
self . strides . clone ( )
298
324
} ;
@@ -381,7 +407,8 @@ where
381
407
return ;
382
408
}
383
409
sort_axes_impl ( & mut a. dim , & mut a. strides , & mut b. dim , & mut b. strides ) ;
384
- debug_assert ! ( a. is_standard_layout( ) ) ;
410
+ debug_assert ! ( a. is_standard_layout( ) , "not std layout dim: {:?}, strides: {:?}" ,
411
+ a. shape( ) , a. strides( ) ) ;
385
412
}
386
413
387
414
fn sort_axes_impl < D > ( adim : & mut D , astrides : & mut D , bdim : & mut D , bstrides : & mut D )
0 commit comments