@@ -46,15 +46,12 @@ pub fn stride_offset(n: Ix, stride: Ix) -> isize {
46
46
/// There is overlap if, when iterating through the dimensions in order of
47
47
/// increasing stride, the current stride is less than or equal to the maximum
48
48
/// 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.
52
49
pub fn dim_stride_overlap < D : Dimension > ( dim : & D , strides : & D ) -> bool {
53
50
let order = strides. _fastest_varying_stride_order ( ) ;
54
51
let mut sum_prev_offsets = 0 ;
55
52
for & index in order. slice ( ) {
56
53
let d = dim[ index] ;
57
- let s = strides[ index] as isize ;
54
+ let s = ( strides[ index] as isize ) . abs ( ) ;
58
55
match d {
59
56
0 => return false ,
60
57
1 => { }
@@ -210,11 +207,7 @@ where
210
207
///
211
208
/// 2. The product of non-zero axis lengths must not exceed `isize::MAX`.
212
209
///
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
218
211
/// between the least address and greatest address accessible by moving
219
212
/// along all axes must be ≤ `data.len()`. (It's fine in this case to move
220
213
/// one byte past the end of the slice since the pointers will be offset but
@@ -225,13 +218,19 @@ where
225
218
/// `data.len()`. This and #3 ensure that all dereferenceable pointers point
226
219
/// to elements within the slice.
227
220
///
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
229
222
/// indices.
230
223
///
231
224
/// Note that since slices cannot contain more than `isize::MAX` bytes,
232
225
/// condition 4 is sufficient to guarantee that the absolute difference in
233
226
/// units of `A` and in units of bytes between the least address and greatest
234
227
/// 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.)
235
234
pub ( crate ) fn can_index_slice < A , D : Dimension > (
236
235
data : & [ A ] ,
237
236
dim : & D ,
@@ -248,7 +247,7 @@ fn can_index_slice_impl<D: Dimension>(
248
247
dim : & D ,
249
248
strides : & D ,
250
249
) -> Result < ( ) , ShapeError > {
251
- // Check condition 4 .
250
+ // Check condition 3 .
252
251
let is_empty = dim. slice ( ) . iter ( ) . any ( |& d| d == 0 ) ;
253
252
if is_empty && max_offset > data_len {
254
253
return Err ( from_kind ( ErrorKind :: OutOfBounds ) ) ;
@@ -257,15 +256,7 @@ fn can_index_slice_impl<D: Dimension>(
257
256
return Err ( from_kind ( ErrorKind :: OutOfBounds ) ) ;
258
257
}
259
258
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.
269
260
if !is_empty && dim_stride_overlap ( dim, strides) {
270
261
return Err ( from_kind ( ErrorKind :: Unsupported ) ) ;
271
262
}
@@ -289,6 +280,19 @@ pub fn stride_offset_checked(dim: &[Ix], strides: &[Ix], index: &[Ix]) -> Option
289
280
Some ( offset)
290
281
}
291
282
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
+
292
296
/// Implementation-specific extensions to `Dimension`
293
297
pub trait DimensionExt {
294
298
// 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) {
394
398
( start, end, step)
395
399
}
396
400
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
+
397
414
/// Modify dimension, stride and return data pointer offset
398
415
///
399
416
/// **Panics** if stride is 0 or if any index is out of bounds.
@@ -693,13 +710,21 @@ mod test {
693
710
let dim = ( 2 , 3 , 2 ) . into_dimension ( ) ;
694
711
let strides = ( 5 , 2 , 1 ) . into_dimension ( ) ;
695
712
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) ) ;
696
715
let strides = ( 6 , 2 , 1 ) . into_dimension ( ) ;
697
716
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) ) ;
698
719
let strides = ( 6 , 0 , 1 ) . into_dimension ( ) ;
699
720
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) ) ;
700
723
let dim = ( 2 , 2 ) . into_dimension ( ) ;
701
724
let strides = ( 3 , 2 ) . into_dimension ( ) ;
702
725
assert ! ( !super :: dim_stride_overlap( & dim, & strides) ) ;
726
+ let strides = ( 3 , -2isize as usize ) . into_dimension ( ) ;
727
+ assert ! ( !super :: dim_stride_overlap( & dim, & strides) ) ;
703
728
}
704
729
705
730
#[ test]
@@ -736,7 +761,7 @@ mod test {
736
761
can_index_slice :: < i32 , _ > ( & [ 1 ] , & Ix1 ( 2 ) , & Ix1 ( 1 ) ) . unwrap_err ( ) ;
737
762
can_index_slice :: < i32 , _ > ( & [ 1 , 2 ] , & Ix1 ( 2 ) , & Ix1 ( 0 ) ) . unwrap_err ( ) ;
738
763
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 ( ) ;
740
765
}
741
766
742
767
#[ test]
0 commit comments