@@ -298,15 +298,6 @@ impl<T, D> PyArray<T, D> {
298298 self . len ( ) == 0
299299 }
300300
301- fn strides_usize ( & self ) -> & [ usize ] {
302- let n = self . ndim ( ) ;
303- let ptr = self . as_array_ptr ( ) ;
304- unsafe {
305- let p = ( * ptr) . strides ;
306- slice:: from_raw_parts ( p as * const _ , n)
307- }
308- }
309-
310301 /// Returns the pointer to the first element of the inner array.
311302 pub ( crate ) unsafe fn data ( & self ) -> * mut T {
312303 let ptr = self . as_array_ptr ( ) ;
@@ -318,20 +309,50 @@ impl<T, D> PyArray<T, D> {
318309 }
319310}
320311
312+ struct InvertedAxises ( Vec < Axis > ) ;
313+
314+ impl InvertedAxises {
315+ fn invert < S : RawData , D : Dimension > ( self , array : & mut ArrayBase < S , D > ) {
316+ for axis in self . 0 {
317+ array. invert_axis ( axis) ;
318+ }
319+ }
320+ }
321+
321322impl < T : Element , D : Dimension > PyArray < T , D > {
322323 /// Same as [shape](#method.shape), but returns `D`
323324 #[ inline( always) ]
324325 pub fn dims ( & self ) -> D {
325326 D :: from_dimension ( & Dim ( self . shape ( ) ) ) . expect ( "PyArray::dims different dimension" )
326327 }
327328
328- fn ndarray_shape ( & self ) -> StrideShape < D > {
329+ fn ndarray_shape_ptr ( & self ) -> ( StrideShape < D > , * mut T , InvertedAxises ) {
330+ const ERR_MSG : & str = "PyArray::ndarray_shape: dimension mismatching" ;
331+ let shape_slice = self . shape ( ) ;
329332 let shape: Shape < _ > = Dim ( self . dims ( ) ) . into ( ) ;
330- let size = mem:: size_of :: < T > ( ) ;
331- let mut st = D :: from_dimension ( & Dim ( self . strides_usize ( ) ) )
332- . expect ( "PyArray::ndarray_shape: dimension mismatching" ) ;
333- st. slice_mut ( ) . iter_mut ( ) . for_each ( |e| * e /= size) ;
334- shape. strides ( st)
333+ let sizeof_t = mem:: size_of :: < T > ( ) ;
334+ let strides = self . strides ( ) ;
335+ let mut new_strides = D :: zeros ( strides. len ( ) ) ;
336+ let mut data_ptr = unsafe { self . data ( ) } ;
337+ let mut inverted_axises = vec ! [ ] ;
338+ for i in 0 ..strides. len ( ) {
339+ // TODO(kngwyu): Replace this hacky negative strides support with
340+ // a proper constructor, when it's implemented.
341+ // See https://github.com/rust-ndarray/ndarray/issues/842 for more.
342+ if strides[ i] < 0 {
343+ // Move the pointer to the start position
344+ let offset = strides[ i] * ( shape_slice[ i] as isize - 1 ) / sizeof_t as isize ;
345+ unsafe {
346+ data_ptr = data_ptr. offset ( offset) ;
347+ }
348+ new_strides[ i] = ( -strides[ i] ) as usize / sizeof_t;
349+ inverted_axises. push ( Axis ( i) ) ;
350+ } else {
351+ new_strides[ i] = strides[ i] as usize / sizeof_t;
352+ }
353+ }
354+ let st = D :: from_dimension ( & Dim ( new_strides) ) . expect ( ERR_MSG ) ;
355+ ( shape. strides ( st) , data_ptr, InvertedAxises ( inverted_axises) )
335356 }
336357
337358 /// Creates a new uninitialized PyArray in python heap.
@@ -632,7 +653,10 @@ impl<T: Element, D: Dimension> PyArray<T, D> {
632653 /// If the internal array is not readonly and can be mutated from Python code,
633654 /// holding the `ArrayView` might cause undefined behavior.
634655 pub unsafe fn as_array ( & self ) -> ArrayView < ' _ , T , D > {
635- ArrayView :: from_shape_ptr ( self . ndarray_shape ( ) , self . data ( ) )
656+ let ( shape, ptr, inverted_axises) = self . ndarray_shape_ptr ( ) ;
657+ let mut res = ArrayView :: from_shape_ptr ( shape, ptr) ;
658+ inverted_axises. invert ( & mut res) ;
659+ res
636660 }
637661
638662 /// Returns the internal array as `ArrayViewMut`. See also [`as_array`](#method.as_array).
@@ -641,7 +665,10 @@ impl<T: Element, D: Dimension> PyArray<T, D> {
641665 /// If another reference to the internal data exists(e.g., `&[T]` or `ArrayView`),
642666 /// it might cause undefined behavior.
643667 pub unsafe fn as_array_mut ( & self ) -> ArrayViewMut < ' _ , T , D > {
644- ArrayViewMut :: from_shape_ptr ( self . ndarray_shape ( ) , self . data ( ) )
668+ let ( shape, ptr, inverted_axises) = self . ndarray_shape_ptr ( ) ;
669+ let mut res = ArrayViewMut :: from_shape_ptr ( shape, ptr) ;
670+ inverted_axises. invert ( & mut res) ;
671+ res
645672 }
646673
647674 /// Get a copy of `PyArray` as
0 commit comments