@@ -106,6 +106,7 @@ linearindexing(::LinearIndexing, ::LinearIndexing) = LinearSlow()
106
106
107
107
# # Bounds checking ##
108
108
@generated function trailingsize {T,N,n} (A:: AbstractArray{T,N} , :: Type{Val{n}} )
109
+ (isa (n, Int) && isa (N, Int)) || error (" Must have concrete type" )
109
110
n > N && return 1
110
111
ex = :(size (A, $ n))
111
112
for m = n+ 1 : N
@@ -115,52 +116,65 @@ linearindexing(::LinearIndexing, ::LinearIndexing) = LinearSlow()
115
116
end
116
117
117
118
# check along a single dimension
118
- checkbounds (:: Type{Bool} , inds:: UnitRange , i) = throw (ArgumentError (" unable to check bounds for indices of type $(typeof (i)) " ))
119
- checkbounds (:: Type{Bool} , inds:: UnitRange , i:: Real ) = first (inds) <= i <= last (inds)
120
- checkbounds (:: Type{Bool} , inds:: UnitRange , :: Colon ) = true
121
- function checkbounds (:: Type{Bool} , inds:: UnitRange , r:: Range )
119
+ checkindex (:: Type{Bool} , inds:: UnitRange , i) = throw (ArgumentError (" unable to check bounds for indices of type $(typeof (i)) " ))
120
+ checkindex (:: Type{Bool} , inds:: UnitRange , i:: Real ) = ( first (inds) <= i) & (i <= last (inds) )
121
+ checkindex (:: Type{Bool} , inds:: UnitRange , :: Colon ) = true
122
+ function checkindex (:: Type{Bool} , inds:: UnitRange , r:: Range )
122
123
@_propagate_inbounds_meta
123
- isempty (r) | (checkbounds (Bool, inds, first (r)) & checkbounds (Bool, inds, last (r)))
124
+ isempty (r) | (checkindex (Bool, inds, first (r)) & checkindex (Bool, inds, last (r)))
124
125
end
125
- checkbounds {N} (:: Type{Bool} , indx:: UnitRange , I:: AbstractArray{Bool,N} ) = N == 1 && indx == indices (I,1 )
126
- function checkbounds (:: Type{Bool} , inds:: UnitRange , I:: AbstractArray )
126
+ checkindex {N} (:: Type{Bool} , indx:: UnitRange , I:: AbstractArray{Bool,N} ) = N == 1 && indx == indices (I,1 )
127
+ function checkindex (:: Type{Bool} , inds:: UnitRange , I:: AbstractArray )
127
128
@_inline_meta
128
129
b = true
129
130
for i in I
130
- b &= checkbounds (Bool, inds, i)
131
+ b &= checkindex (Bool, inds, i)
131
132
end
132
133
b
133
134
end
134
135
135
- # check all dimensions
136
- function checkbounds {N,T} (:: Type{Bool} , inds :: NTuple{N,UnitRange} , I1 :: T , I... )
136
+ # check all indices/ dimensions
137
+ function checkbounds (:: Type{Bool} , A :: AbstractArray , I... )
137
138
@_inline_meta
138
- checkbounds (Bool, inds[1 ], I1) & checkbounds (Bool, tail (inds), I... )
139
+ # checked::NTuple{M} means we have checked dimensions 1:M-1, now
140
+ # need to check dimension M. checked[M] indicates whether all the
141
+ # previous ones are in-bounds.
142
+ # By growing checked, it allows us to test whether we've processed
143
+ # the same number of dimensions as the array, even while
144
+ # supporting CartesianIndex
145
+ checked = (true ,)
146
+ _chkbnds (A, (true ,), I... )
147
+ end
148
+ # Single logical array indexing:
149
+ _chkbnds (A:: AbstractArray , :: NTuple{1,Bool} , I:: AbstractArray{Bool} ) = indices (A) == indices (I)
150
+ _chkbnds (A:: AbstractVector , :: NTuple{1,Bool} , I:: AbstractVector{Bool} ) = indices (A) == indices (I)
151
+ _chkbnds (A:: AbstractArray , :: NTuple{1,Bool} , I:: AbstractVector{Bool} ) = length (A) == length (I)
152
+ # When all indices have been checked:
153
+ _chkbnds {M} (A, checked:: NTuple{M,Bool} ) = checked[M]
154
+ # When the number of indices matches the array dimensionality:
155
+ function _chkbnds {T,N} (A:: AbstractArray{T,N} , checked:: NTuple{N,Bool} , I1)
156
+ @_inline_meta
157
+ checked[N] & checkindex (Bool, indices (A, N), I1)
139
158
end
140
- checkbounds (:: Type{Bool} , inds:: Tuple{UnitRange} , I1) = (@_inline_meta ; checkbounds (Bool, inds[1 ], I1))
141
- checkbounds {N} (:: Type{Bool} , inds:: NTuple{N,UnitRange} , I1) = (@_inline_meta ; checkbounds (Bool, 1 : prod (map (length, inds)), I1)) # TODO : eliminate (partial linear indexing)
142
- checkbounds {N} (:: Type{Bool} , inds:: NTuple{N,UnitRange} ) = (@_inline_meta ; checkbounds (Bool, inds, 1 )) # for a[]
143
-
144
- checkbounds (:: Type{Bool} , inds:: Tuple{} , i) = (@_inline_meta ; checkbounds (Bool, 1 : 1 , i))
145
- function checkbounds (:: Type{Bool} , inds:: Tuple{} , i, I... )
159
+ # When the last checked dimension is not equal to the array dimensionality:
160
+ # TODO : when deprecating partial linear indexing, change to 1:trailingsize(...) to 1:1
161
+ function _chkbnds {T,N,M} (A:: AbstractArray{T,N} , checked:: NTuple{M,Bool} , I1)
146
162
@_inline_meta
147
- checkbounds (Bool, 1 : 1 , i) & checkbounds (Bool, ( ), I ... )
163
+ checked[M] & checkindex (Bool, 1 : trailingsize (A, Val{M} ), I1 )
148
164
end
149
- # Prevent allocation of a GC frame by hiding the BoundsError in a noinline function
165
+ # Checking an interior dimension:
166
+ function _chkbnds {T,N,M} (A:: AbstractArray{T,N} , checked:: NTuple{M,Bool} , I1, I... )
167
+ @_inline_meta
168
+ # grow checked by one
169
+ newchecked = (checked... , checked[M] & checkindex (Bool, indices (A, M), I1))
170
+ _chkbnds (A, newchecked, I... )
171
+ end
172
+
150
173
throw_boundserror (A, I) = (@_noinline_meta ; throw (BoundsError (A, I)))
151
174
152
- # Don't define index types on checkbounds to make extending easier
153
- checkbounds (A:: AbstractArray , I... ) = (@_inline_meta ; _internal_checkbounds (A, I... ))
154
- # The internal function is named _internal_checkbounds since there had been a
155
- # _checkbounds previously that meant something different.
156
- _internal_checkbounds (A:: AbstractArray ) = true
157
- _internal_checkbounds (A:: AbstractArray , I:: AbstractArray{Bool} ) = indices (A) == indices (I) || throw_boundserror (A, I)
158
- _internal_checkbounds (A:: AbstractVector , I:: AbstractVector{Bool} ) = indices (A) == indices (I) || throw_boundserror (A, I)
159
- _internal_checkbounds (A:: AbstractArray , I:: AbstractVector{Bool} ) = length (A) == length (I) || throw_boundserror (A, I)
160
- function _internal_checkbounds (A:: AbstractArray , I1, I... )
161
- # having I1 seems important for good codegen
175
+ function checkbounds (A:: AbstractArray , I... )
162
176
@_inline_meta
163
- checkbounds (Bool, indices (A), I1, I... ) || throw_boundserror (A, (I1, I ... ) )
177
+ checkbounds (Bool, A, I... ) || throw_boundserror (A, I )
164
178
end
165
179
166
180
# See also specializations in multidimensional
584
598
585
599
typealias RangeVecIntList{A<: AbstractVector{Int} } Union{Tuple{Vararg{Union{Range, AbstractVector{Int}}}}, AbstractVector{UnitRange{Int}}, AbstractVector{Range{Int}}, AbstractVector{A}}
586
600
587
- get (A:: AbstractArray , i:: Integer , default) = checkbounds (Bool, indices (A) , i) ? A[i] : default
601
+ get (A:: AbstractArray , i:: Integer , default) = checkbounds (Bool, A , i) ? A[i] : default
588
602
get (A:: AbstractArray , I:: Tuple{} , default) = similar (A, typeof (default), 0 )
589
- get (A:: AbstractArray , I:: Dims , default) = checkbounds (Bool, indices (A) , I... ) ? A[I... ] : default
603
+ get (A:: AbstractArray , I:: Dims , default) = checkbounds (Bool, A , I... ) ? A[I... ] : default
590
604
591
605
function get! {T} (X:: AbstractArray{T} , A:: AbstractArray , I:: Union{Range, AbstractVector{Int}} , default:: T )
592
606
ind = findin (I, 1 : length (A))
0 commit comments