@@ -83,9 +83,27 @@ pub trait Dimension : Clone + Eq + Debug + Send + Sync + Default +
83
83
self . slice ( ) . iter ( ) . fold ( 1 , |s, & a| s * a as usize )
84
84
}
85
85
86
- /// Compute the size while checking for overflow.
86
+ /// Compute the size (number of elements) while checking for overflow.
87
+ ///
88
+ /// Returns `None` if the product of non-zero axis lengths overflows
89
+ /// `isize`.
90
+ ///
91
+ /// If `dim.size_checked()` returns `Some(size)`, a `Vec` is created of
92
+ /// length `size`, and `strides` are created with `self.default_strides()`
93
+ /// or `self.fortran_strides()`, then the invariants are met to construct
94
+ /// an owned `Array` from the `Vec`, `dim`, and `strides`. (See the docs of
95
+ /// `can_index_slice_not_custom` for a slightly more general case.)
87
96
fn size_checked ( & self ) -> Option < usize > {
88
- self . slice ( ) . iter ( ) . fold ( Some ( 1 ) , |s, & a| s. and_then ( |s_| s_. checked_mul ( a) ) )
97
+ let size_nonzero = self
98
+ . slice ( )
99
+ . iter ( )
100
+ . filter ( |& & d| d != 0 )
101
+ . try_fold ( 1usize , |acc, & d| acc. checked_mul ( d) ) ?;
102
+ if size_nonzero > :: std:: isize:: MAX as usize {
103
+ None
104
+ } else {
105
+ Some ( self . size ( ) )
106
+ }
89
107
}
90
108
91
109
#[ doc( hidden) ]
@@ -109,12 +127,17 @@ pub trait Dimension : Clone + Eq + Debug + Send + Sync + Default +
109
127
self . slice ( ) == rhs. slice ( )
110
128
}
111
129
130
+ /// Returns the strides for a standard layout array with the given shape.
131
+ ///
132
+ /// If the array is non-empty, the strides result in contiguous layout; if
133
+ /// the array is empty, the strides are all zeros.
112
134
#[ doc( hidden) ]
113
135
fn default_strides ( & self ) -> Self {
114
136
// Compute default array strides
115
137
// Shape (a, b, c) => Give strides (b * c, c, 1)
116
- let mut strides = self . clone ( ) ;
117
- {
138
+ let mut strides = Self :: zeros ( self . ndim ( ) ) ;
139
+ // For empty arrays, use all zero strides.
140
+ if self . slice ( ) . iter ( ) . all ( |& d| d != 0 ) {
118
141
let mut it = strides. slice_mut ( ) . iter_mut ( ) . rev ( ) ;
119
142
// Set first element to 1
120
143
while let Some ( rs) = it. next ( ) {
@@ -130,12 +153,17 @@ pub trait Dimension : Clone + Eq + Debug + Send + Sync + Default +
130
153
strides
131
154
}
132
155
156
+ /// Returns the strides for a Fortran layout array with the given shape.
157
+ ///
158
+ /// If the array is non-empty, the strides result in contiguous layout; if
159
+ /// the array is empty, the strides are all zeros.
133
160
#[ doc( hidden) ]
134
161
fn fortran_strides ( & self ) -> Self {
135
162
// Compute fortran array strides
136
163
// Shape (a, b, c) => Give strides (1, a, a * b)
137
- let mut strides = self . clone ( ) ;
138
- {
164
+ let mut strides = Self :: zeros ( self . ndim ( ) ) ;
165
+ // For empty arrays, use all zero strides.
166
+ if self . slice ( ) . iter ( ) . all ( |& d| d != 0 ) {
139
167
let mut it = strides. slice_mut ( ) . iter_mut ( ) ;
140
168
// Set first element to 1
141
169
while let Some ( rs) = it. next ( ) {
@@ -428,11 +456,22 @@ impl Dimension for Dim<[Ix; 1]> {
428
456
#[ inline]
429
457
fn size ( & self ) -> usize { get ! ( self , 0 ) }
430
458
#[ inline]
431
- fn size_checked ( & self ) -> Option < usize > { Some ( get ! ( self , 0 ) ) }
459
+ fn size_checked ( & self ) -> Option < usize > {
460
+ let size = get ! ( self , 0 ) ;
461
+ if size <= :: std:: isize:: MAX as usize {
462
+ Some ( size)
463
+ } else {
464
+ None
465
+ }
466
+ }
432
467
433
468
#[ inline]
434
469
fn default_strides ( & self ) -> Self {
435
- Ix1 ( 1 )
470
+ if get ! ( self , 0 ) == 0 {
471
+ Ix1 ( 0 )
472
+ } else {
473
+ Ix1 ( 1 )
474
+ }
436
475
}
437
476
438
477
#[ inline]
@@ -533,7 +572,15 @@ impl Dimension for Dim<[Ix; 2]> {
533
572
fn size_checked ( & self ) -> Option < usize > {
534
573
let m = get ! ( self , 0 ) ;
535
574
let n = get ! ( self , 1 ) ;
536
- ( m as usize ) . checked_mul ( n as usize )
575
+ let size = m. checked_mul ( n) ?;
576
+ if m <= :: std:: isize:: MAX as usize
577
+ && n <= :: std:: isize:: MAX as usize
578
+ && size <= :: std:: isize:: MAX as usize
579
+ {
580
+ Some ( size)
581
+ } else {
582
+ None
583
+ }
537
584
}
538
585
539
586
#[ inline]
@@ -548,13 +595,23 @@ impl Dimension for Dim<[Ix; 2]> {
548
595
549
596
#[ inline]
550
597
fn default_strides ( & self ) -> Self {
551
- // Compute default array strides
552
- // Shape (a, b, c) => Give strides (b * c, c, 1)
553
- Ix2 ( get ! ( self , 1 ) , 1 )
598
+ let m = get ! ( self , 0 ) ;
599
+ let n = get ! ( self , 1 ) ;
600
+ if m == 0 || n == 0 {
601
+ Ix2 ( 0 , 0 )
602
+ } else {
603
+ Ix2 ( n, 1 )
604
+ }
554
605
}
555
606
#[ inline]
556
607
fn fortran_strides ( & self ) -> Self {
557
- Ix2 ( 1 , get ! ( self , 0 ) )
608
+ let m = get ! ( self , 0 ) ;
609
+ let n = get ! ( self , 1 ) ;
610
+ if m == 0 || n == 0 {
611
+ Ix2 ( 0 , 0 )
612
+ } else {
613
+ Ix2 ( 1 , m)
614
+ }
558
615
}
559
616
560
617
#[ inline]
0 commit comments