@@ -46,15 +46,12 @@ pub fn stride_offset(n: Ix, stride: Ix) -> isize {
4646/// There is overlap if, when iterating through the dimensions in order of
4747/// increasing stride, the current stride is less than or equal to the maximum
4848/// possible offset along the preceding axes. (Axes of length ≤1 are ignored.)
49- ///
50- /// The current implementation assumes that strides of axes with length > 1 are
51- /// nonnegative. Additionally, it does not check for overflow.
5249pub fn dim_stride_overlap < D : Dimension > ( dim : & D , strides : & D ) -> bool {
5350 let order = strides. _fastest_varying_stride_order ( ) ;
5451 let mut sum_prev_offsets = 0 ;
5552 for & index in order. slice ( ) {
5653 let d = dim[ index] ;
57- let s = strides[ index] as isize ;
54+ let s = ( strides[ index] as isize ) . abs ( ) ;
5855 match d {
5956 0 => return false ,
6057 1 => { }
@@ -210,8 +207,7 @@ where
210207///
211208/// 2. The product of non-zero axis lengths must not exceed `isize::MAX`.
212209///
213- /// 3. For axes with length > 1, the stride must be nonnegative. This is
214- /// necessary to make sure the pointer cannot move backwards outside the
210+ /// 3. For axes with length > 1, the pointer cannot move outside the
215211/// slice. For axes with length ≤ 1, the stride can be anything.
216212///
217213/// 4. If the array will be empty (any axes are zero-length), the difference
@@ -257,14 +253,6 @@ fn can_index_slice_impl<D: Dimension>(
257253 return Err ( from_kind ( ErrorKind :: OutOfBounds ) ) ;
258254 }
259255
260- // Check condition 3.
261- for ( & d, & s) in izip ! ( dim. slice( ) , strides. slice( ) ) {
262- let s = s as isize ;
263- if d > 1 && s < 0 {
264- return Err ( from_kind ( ErrorKind :: Unsupported ) ) ;
265- }
266- }
267-
268256 // Check condition 5.
269257 if !is_empty && dim_stride_overlap ( dim, strides) {
270258 return Err ( from_kind ( ErrorKind :: Unsupported ) ) ;
@@ -394,6 +382,19 @@ fn to_abs_slice(axis_len: usize, slice: Slice) -> (usize, usize, isize) {
394382 ( start, end, step)
395383}
396384
385+ /// This function computes the offset from the logically first element to the first element in
386+ /// memory of the array. The result is always <= 0.
387+ pub fn offset_from_ptr_to_memory ( dim : & [ Ix ] , strides : & [ Ix ] ) -> isize {
388+ let offset = izip ! ( dim, strides) . fold ( 0 , |_offset, ( d, s) | {
389+ if ( * s as isize ) < 0 {
390+ _offset + * s as isize * ( * d as isize - 1 )
391+ } else {
392+ _offset
393+ }
394+ } ) ;
395+ offset
396+ }
397+
397398/// Modify dimension, stride and return data pointer offset
398399///
399400/// **Panics** if stride is 0 or if any index is out of bounds.
@@ -693,13 +694,21 @@ mod test {
693694 let dim = ( 2 , 3 , 2 ) . into_dimension ( ) ;
694695 let strides = ( 5 , 2 , 1 ) . into_dimension ( ) ;
695696 assert ! ( super :: dim_stride_overlap( & dim, & strides) ) ;
697+ let strides = ( -5isize as usize , 2 , -1isize as usize ) . into_dimension ( ) ;
698+ assert ! ( super :: dim_stride_overlap( & dim, & strides) ) ;
696699 let strides = ( 6 , 2 , 1 ) . into_dimension ( ) ;
697700 assert ! ( !super :: dim_stride_overlap( & dim, & strides) ) ;
701+ let strides = ( 6 , -2isize as usize , 1 ) . into_dimension ( ) ;
702+ assert ! ( !super :: dim_stride_overlap( & dim, & strides) ) ;
698703 let strides = ( 6 , 0 , 1 ) . into_dimension ( ) ;
699704 assert ! ( super :: dim_stride_overlap( & dim, & strides) ) ;
705+ let strides = ( -6isize as usize , 0 , 1 ) . into_dimension ( ) ;
706+ assert ! ( super :: dim_stride_overlap( & dim, & strides) ) ;
700707 let dim = ( 2 , 2 ) . into_dimension ( ) ;
701708 let strides = ( 3 , 2 ) . into_dimension ( ) ;
702709 assert ! ( !super :: dim_stride_overlap( & dim, & strides) ) ;
710+ let strides = ( 3 , -2isize as usize ) . into_dimension ( ) ;
711+ assert ! ( !super :: dim_stride_overlap( & dim, & strides) ) ;
703712 }
704713
705714 #[ test]
@@ -736,7 +745,7 @@ mod test {
736745 can_index_slice :: < i32 , _ > ( & [ 1 ] , & Ix1 ( 2 ) , & Ix1 ( 1 ) ) . unwrap_err ( ) ;
737746 can_index_slice :: < i32 , _ > ( & [ 1 , 2 ] , & Ix1 ( 2 ) , & Ix1 ( 0 ) ) . unwrap_err ( ) ;
738747 can_index_slice :: < i32 , _ > ( & [ 1 , 2 ] , & Ix1 ( 2 ) , & Ix1 ( 1 ) ) . unwrap ( ) ;
739- can_index_slice :: < i32 , _ > ( & [ 1 , 2 ] , & Ix1 ( 2 ) , & Ix1 ( -1isize as usize ) ) . unwrap_err ( ) ;
748+ can_index_slice :: < i32 , _ > ( & [ 1 , 2 ] , & Ix1 ( 2 ) , & Ix1 ( -1isize as usize ) ) . unwrap ( ) ;
740749 }
741750
742751 #[ test]
0 commit comments