@@ -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,11 +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
215- /// slice. For axes with length ≤ 1, the stride can be anything.
216- ///
217- /// 4. If the array will be empty (any axes are zero-length), the difference
210+ /// 3. If the array will be empty (any axes are zero-length), the difference
218211/// between the least address and greatest address accessible by moving
219212/// along all axes must be ≤ `data.len()`. (It's fine in this case to move
220213/// one byte past the end of the slice since the pointers will be offset but
@@ -225,13 +218,19 @@ where
225218/// `data.len()`. This and #3 ensure that all dereferenceable pointers point
226219/// to elements within the slice.
227220///
228- /// 5 . The strides must not allow any element to be referenced by two different
221+ /// 4 . The strides must not allow any element to be referenced by two different
229222/// indices.
230223///
231224/// Note that since slices cannot contain more than `isize::MAX` bytes,
232225/// condition 4 is sufficient to guarantee that the absolute difference in
233226/// units of `A` and in units of bytes between the least address and greatest
234227/// address accessible by moving along all axes does not exceed `isize::MAX`.
228+ ///
229+ /// Warning: This function is sufficient to check the invariants of ArrayBase only
230+ /// if the pointer to the first element of the array is chosen such that the element
231+ /// with the smallest memory address is at the start of data. (In other words, the
232+ /// pointer to the first element of the array must be computed using offset_from_ptr_to_memory
233+ /// so that negative strides are correctly handled.)
235234pub ( crate ) fn can_index_slice < A , D : Dimension > (
236235 data : & [ A ] ,
237236 dim : & D ,
@@ -248,7 +247,7 @@ fn can_index_slice_impl<D: Dimension>(
248247 dim : & D ,
249248 strides : & D ,
250249) -> Result < ( ) , ShapeError > {
251- // Check condition 4 .
250+ // Check condition 3 .
252251 let is_empty = dim. slice ( ) . iter ( ) . any ( |& d| d == 0 ) ;
253252 if is_empty && max_offset > data_len {
254253 return Err ( from_kind ( ErrorKind :: OutOfBounds ) ) ;
@@ -257,15 +256,7 @@ fn can_index_slice_impl<D: Dimension>(
257256 return Err ( from_kind ( ErrorKind :: OutOfBounds ) ) ;
258257 }
259258
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-
268- // Check condition 5.
259+ // Check condition 4.
269260 if !is_empty && dim_stride_overlap ( dim, strides) {
270261 return Err ( from_kind ( ErrorKind :: Unsupported ) ) ;
271262 }
@@ -289,6 +280,19 @@ pub fn stride_offset_checked(dim: &[Ix], strides: &[Ix], index: &[Ix]) -> Option
289280 Some ( offset)
290281}
291282
283+ /// Checks if strides are non-negative.
284+ pub fn strides_non_negative < D > ( strides : & D ) -> Result < ( ) , ShapeError >
285+ where
286+ D : Dimension ,
287+ {
288+ for & stride in strides. slice ( ) {
289+ if ( stride as isize ) < 0 {
290+ return Err ( from_kind ( ErrorKind :: Unsupported ) ) ;
291+ }
292+ }
293+ Ok ( ( ) )
294+ }
295+
292296/// Implementation-specific extensions to `Dimension`
293297pub trait DimensionExt {
294298 // note: many extensions go in the main trait if they need to be special-
@@ -394,6 +398,19 @@ fn to_abs_slice(axis_len: usize, slice: Slice) -> (usize, usize, isize) {
394398 ( start, end, step)
395399}
396400
401+ /// This function computes the offset from the logically first element to the first element in
402+ /// memory of the array. The result is always <= 0.
403+ pub fn offset_from_ptr_to_memory < D : Dimension > ( dim : & D , strides : & D ) -> isize {
404+ let offset = izip ! ( dim. slice( ) , strides. slice( ) ) . fold ( 0 , |_offset, ( d, s) | {
405+ if ( * s as isize ) < 0 {
406+ _offset + * s as isize * ( * d as isize - 1 )
407+ } else {
408+ _offset
409+ }
410+ } ) ;
411+ offset
412+ }
413+
397414/// Modify dimension, stride and return data pointer offset
398415///
399416/// **Panics** if stride is 0 or if any index is out of bounds.
@@ -693,13 +710,21 @@ mod test {
693710 let dim = ( 2 , 3 , 2 ) . into_dimension ( ) ;
694711 let strides = ( 5 , 2 , 1 ) . into_dimension ( ) ;
695712 assert ! ( super :: dim_stride_overlap( & dim, & strides) ) ;
713+ let strides = ( -5isize as usize , 2 , -1isize as usize ) . into_dimension ( ) ;
714+ assert ! ( super :: dim_stride_overlap( & dim, & strides) ) ;
696715 let strides = ( 6 , 2 , 1 ) . into_dimension ( ) ;
697716 assert ! ( !super :: dim_stride_overlap( & dim, & strides) ) ;
717+ let strides = ( 6 , -2isize as usize , 1 ) . into_dimension ( ) ;
718+ assert ! ( !super :: dim_stride_overlap( & dim, & strides) ) ;
698719 let strides = ( 6 , 0 , 1 ) . into_dimension ( ) ;
699720 assert ! ( super :: dim_stride_overlap( & dim, & strides) ) ;
721+ let strides = ( -6isize as usize , 0 , 1 ) . into_dimension ( ) ;
722+ assert ! ( super :: dim_stride_overlap( & dim, & strides) ) ;
700723 let dim = ( 2 , 2 ) . into_dimension ( ) ;
701724 let strides = ( 3 , 2 ) . into_dimension ( ) ;
702725 assert ! ( !super :: dim_stride_overlap( & dim, & strides) ) ;
726+ let strides = ( 3 , -2isize as usize ) . into_dimension ( ) ;
727+ assert ! ( !super :: dim_stride_overlap( & dim, & strides) ) ;
703728 }
704729
705730 #[ test]
@@ -736,7 +761,7 @@ mod test {
736761 can_index_slice :: < i32 , _ > ( & [ 1 ] , & Ix1 ( 2 ) , & Ix1 ( 1 ) ) . unwrap_err ( ) ;
737762 can_index_slice :: < i32 , _ > ( & [ 1 , 2 ] , & Ix1 ( 2 ) , & Ix1 ( 0 ) ) . unwrap_err ( ) ;
738763 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 ( ) ;
764+ can_index_slice :: < i32 , _ > ( & [ 1 , 2 ] , & Ix1 ( 2 ) , & Ix1 ( -1isize as usize ) ) . unwrap ( ) ;
740765 }
741766
742767 #[ test]
0 commit comments