@@ -256,6 +256,8 @@ impl<A, D> Array<A, D>
256256 A : Clone ,
257257 D : RemoveAxis ,
258258 {
259+ assert_ne ! ( self . ndim( ) , 0 , "Impossible to append to 0-dim array" ) ;
260+ let current_axis_len = self . len_of ( axis) ;
259261 let remaining_shape = self . raw_dim ( ) . remove_axis ( axis) ;
260262 let array_rem_shape = array. raw_dim ( ) . remove_axis ( axis) ;
261263
@@ -275,22 +277,46 @@ impl<A, D> Array<A, D>
275277
276278 let self_is_empty = self . is_empty ( ) ;
277279
278- // array must be empty or have `axis` as the outermost (longest stride)
279- // axis
280- if !( self_is_empty ||
281- self . axes ( ) . max_by_key ( |ax| ax. stride ) . map ( |ax| ax. axis ) == Some ( axis) )
282- {
283- return Err ( ShapeError :: from_kind ( ErrorKind :: IncompatibleLayout ) ) ;
280+ // array must be empty or have `axis` as the outermost (longest stride) axis
281+ if !self_is_empty && current_axis_len > 1 {
282+ // `axis` must be max stride axis or equal to its stride
283+ let max_stride_axis = self . axes ( ) . max_by_key ( |ax| ax. stride ) . unwrap ( ) ;
284+ if max_stride_axis. axis != axis && max_stride_axis. stride > self . stride_of ( axis) {
285+ return Err ( ShapeError :: from_kind ( ErrorKind :: IncompatibleLayout ) ) ;
286+ }
284287 }
285288
286289 // array must be be "full" (have no exterior holes)
287290 if self . len ( ) != self . data . len ( ) {
288291 return Err ( ShapeError :: from_kind ( ErrorKind :: IncompatibleLayout ) ) ;
289292 }
293+
290294 let strides = if self_is_empty {
291- // recompute strides - if the array was previously empty, it could have
292- // zeros in strides.
293- res_dim. default_strides ( )
295+ // recompute strides - if the array was previously empty, it could have zeros in
296+ // strides.
297+ // The new order is based on c/f-contig but must have `axis` as outermost axis.
298+ if axis == Axis ( self . ndim ( ) - 1 ) {
299+ // prefer f-contig when appending to the last axis
300+ // Axis n - 1 is outermost axis
301+ res_dim. fortran_strides ( )
302+ } else {
303+ // Default with modification
304+ res_dim. slice_mut ( ) . swap ( 0 , axis. index ( ) ) ;
305+ let mut strides = res_dim. default_strides ( ) ;
306+ res_dim. slice_mut ( ) . swap ( 0 , axis. index ( ) ) ;
307+ strides. slice_mut ( ) . swap ( 0 , axis. index ( ) ) ;
308+ strides
309+ }
310+ } else if current_axis_len == 1 {
311+ // This is the outermost/longest stride axis; so we find the max across the other axes
312+ let new_stride = self . axes ( ) . fold ( 1 , |acc, ax| {
313+ if ax. axis == axis { acc } else {
314+ Ord :: max ( acc, ax. len as isize * ax. stride )
315+ }
316+ } ) ;
317+ let mut strides = self . strides . clone ( ) ;
318+ strides[ axis. index ( ) ] = new_stride as usize ;
319+ strides
294320 } else {
295321 let strides = self . strides . clone ( ) ;
296322 strides
@@ -380,7 +406,8 @@ where
380406 return ;
381407 }
382408 sort_axes_impl ( & mut a. dim , & mut a. strides , & mut b. dim , & mut b. strides ) ;
383- debug_assert ! ( a. is_standard_layout( ) ) ;
409+ debug_assert ! ( a. is_standard_layout( ) , "not std layout dim: {:?}, strides: {:?}" ,
410+ a. shape( ) , a. strides( ) ) ;
384411}
385412
386413fn sort_axes_impl < D > ( adim : & mut D , astrides : & mut D , bdim : & mut D , bstrides : & mut D )
0 commit comments