@@ -77,9 +77,23 @@ parentindexes(a::AbstractArray) = ntuple(i->1:size(a,i), ndims(a))
77
77
78
78
# # SubArray creation
79
79
# Drops singleton dimensions (those indexed with a scalar)
80
- function slice (A:: AbstractArray , I:: ViewIndex... )
80
+ function slice {T,N} (A:: AbstractArray{T,N} , I:: Vararg{ ViewIndex,N} )
81
81
@_inline_meta
82
82
@boundscheck checkbounds (A, I... )
83
+ unsafe_slice (A, I... )
84
+ end
85
+ function slice (A:: AbstractArray , i:: ViewIndex )
86
+ @_inline_meta
87
+ @boundscheck checkbounds (A, i)
88
+ unsafe_slice (reshape (A, Val{1 }), i)
89
+ end
90
+ function slice {N} (A:: AbstractArray , I:: Vararg{ViewIndex,N} ) # TODO : DEPRECATE FOR #14770
91
+ @_inline_meta
92
+ @boundscheck checkbounds (A, I... )
93
+ unsafe_slice (reshape (A, Val{N}), I... )
94
+ end
95
+ function unsafe_slice {T,N} (A:: AbstractArray{T,N} , I:: Vararg{ViewIndex,N} )
96
+ @_inline_meta
83
97
J = to_indexes (I... )
84
98
SubArray (A, J, index_shape (A, J... ))
85
99
end
@@ -89,9 +103,23 @@ keep_leading_scalars(T::Tuple{Real, Vararg{Real}}) = T
89
103
keep_leading_scalars (T:: Tuple{Real, Vararg{Any}} ) = (@_inline_meta ; (NoSlice (T[1 ]), keep_leading_scalars (tail (T))... ))
90
104
keep_leading_scalars (T:: Tuple{Any, Vararg{Any}} ) = (@_inline_meta ; (T[1 ], keep_leading_scalars (tail (T))... ))
91
105
92
- function sub (A:: AbstractArray , I:: ViewIndex... )
106
+ function sub {T,N} (A:: AbstractArray{T,N} , I:: Vararg{ ViewIndex,N} )
93
107
@_inline_meta
94
108
@boundscheck checkbounds (A, I... )
109
+ unsafe_sub (A, I... )
110
+ end
111
+ function sub (A:: AbstractArray , i:: ViewIndex )
112
+ @_inline_meta
113
+ @boundscheck checkbounds (A, i)
114
+ unsafe_sub (reshape (A, Val{1 }), i)
115
+ end
116
+ function sub {N} (A:: AbstractArray , I:: Vararg{ViewIndex,N} ) # TODO : DEPRECATE FOR #14770
117
+ @_inline_meta
118
+ @boundscheck checkbounds (A, I... )
119
+ unsafe_sub (reshape (A, Val{N}), I... )
120
+ end
121
+ function unsafe_sub {T,N} (A:: AbstractArray{T,N} , I:: Vararg{ViewIndex,N} )
122
+ @_inline_meta
95
123
J = keep_leading_scalars (to_indexes (I... ))
96
124
SubArray (A, J, index_shape (A, J... ))
97
125
end
@@ -100,90 +128,61 @@ end
100
128
#
101
129
# Recursively look through the heads of the parent- and sub-indexes, considering
102
130
# the following cases:
103
- # * Parent index is empty -> ignore trailing scalars, but preserve added dimensions
104
- # * Parent index is Any -> re-index that with the sub-index
105
- # * Parent index is Scalar -> that dimension was dropped, so skip the sub-index and use the index as is
131
+ # * Parent index is array -> re-index that with one or more sub-indexes (one per dimension)
132
+ # * Parent index is Colon -> just use the sub-index as provided
133
+ # * Parent index is scalar -> that dimension was dropped, so skip the sub-index and use the index as is
106
134
#
107
- # Furthermore, we must specially consider the case with one final sub-index,
108
- # as it may be a linear index that spans multiple parent indexes.
109
135
136
+ typealias AbstractZeroDimArray{T} AbstractArray{T, 0 }
110
137
typealias DroppedScalar Union{Real, AbstractCartesianIndex}
111
- # When indexing beyond the parent indices, drop all trailing scalars (they must be 1 to be inbounds)
112
- reindex (V, idxs:: Tuple{} , subidxs:: Tuple{Vararg{DroppedScalar}} ) = ()
113
- # Drop any intervening scalars that are beyond the parent indices but before a nonscalar
114
- reindex (V, idxs:: Tuple{} , subidxs:: Tuple{DroppedScalar, Vararg{Any}} ) =
115
- (@_propagate_inbounds_meta ; (reindex (V, idxs, tail (subidxs))... ))
116
- # And keep the nonscalar index to add the dimension
117
- reindex (V, idxs:: Tuple{} , subidxs:: Tuple{Any, Vararg{Any}} ) =
118
- (@_propagate_inbounds_meta ; (subidxs[1 ], reindex (V, idxs, tail (subidxs))... ))
138
+
139
+ reindex (V, :: Tuple{} , :: Tuple{} ) = ()
119
140
120
141
# Skip dropped scalars, so simply peel them off the parent indices and continue
121
142
reindex (V, idxs:: Tuple{DroppedScalar, Vararg{Any}} , subidxs:: Tuple{Vararg{Any}} ) =
122
143
(@_propagate_inbounds_meta ; (idxs[1 ], reindex (V, tail (idxs), subidxs)... ))
123
144
124
145
# Colons simply pass their subindexes straight through
125
- reindex (V, idxs:: Tuple{Colon} , subidxs:: Tuple{Any} ) =
126
- (@_propagate_inbounds_meta ; (subidxs[1 ],))
127
146
reindex (V, idxs:: Tuple{Colon, Vararg{Any}} , subidxs:: Tuple{Any, Vararg{Any}} ) =
128
147
(@_propagate_inbounds_meta ; (subidxs[1 ], reindex (V, tail (idxs), tail (subidxs))... ))
129
- reindex (V, idxs:: Tuple{Colon, Vararg{Any}} , subidxs:: Tuple{Any} ) =
130
- (@_propagate_inbounds_meta ; (merge_indexes (V, idxs, subidxs[1 ]),))
131
- # As an optimization, we don't need to merge indices if all trailing indices are dropped scalars
132
- reindex (V, idxs:: Tuple{Colon, Vararg{DroppedScalar}} , subidxs:: Tuple{Any} ) =
133
- (@_propagate_inbounds_meta ; (subidxs[1 ], tail (idxs)... ))
134
148
135
149
# Re-index into parent vectors with one subindex
136
- reindex (V, idxs:: Tuple{AbstractVector} , subidxs:: Tuple{Any} ) =
137
- (@_propagate_inbounds_meta ; (idxs[1 ][subidxs[1 ]],))
138
150
reindex (V, idxs:: Tuple{AbstractVector, Vararg{Any}} , subidxs:: Tuple{Any, Vararg{Any}} ) =
139
151
(@_propagate_inbounds_meta ; (idxs[1 ][subidxs[1 ]], reindex (V, tail (idxs), tail (subidxs))... ))
140
- reindex (V, idxs:: Tuple{AbstractVector, Vararg{Any}} , subidxs:: Tuple{Any} ) =
141
- (@_propagate_inbounds_meta ; (merge_indexes (V, idxs, subidxs[1 ]),))
142
- reindex (V, idxs:: Tuple{AbstractVector, Vararg{DroppedScalar}} , subidxs:: Tuple{Any} ) =
143
- (@_propagate_inbounds_meta ; (idxs[1 ][subidxs[1 ]], tail (idxs)... ))
144
152
145
153
# Parent matrices are re-indexed with two sub-indices
146
- reindex (V, idxs:: Tuple{AbstractMatrix} , subidxs:: Tuple{Any} ) =
147
- (@_propagate_inbounds_meta ; (idxs[1 ][subidxs[1 ]],))
148
- reindex (V, idxs:: Tuple{AbstractMatrix} , subidxs:: Tuple{Any, Any} ) =
149
- (@_propagate_inbounds_meta ; (idxs[1 ][subidxs[1 ], subidxs[2 ]],))
150
154
reindex (V, idxs:: Tuple{AbstractMatrix, Vararg{Any}} , subidxs:: Tuple{Any, Any, Vararg{Any}} ) =
151
155
(@_propagate_inbounds_meta ; (idxs[1 ][subidxs[1 ], subidxs[2 ]], reindex (V, tail (idxs), tail (tail (subidxs)))... ))
152
- reindex (V, idxs:: Tuple{AbstractMatrix, Vararg{Any}} , subidxs:: Tuple{Any} ) =
153
- (@_propagate_inbounds_meta ; (merge_indexes (V, idxs, subidxs[1 ]),))
154
- reindex (V, idxs:: Tuple{AbstractMatrix, Vararg{Any}} , subidxs:: Tuple{Any, Any} ) =
155
- (@_propagate_inbounds_meta ; (merge_indexes (V, idxs, subidxs),))
156
- reindex (V, idxs:: Tuple{AbstractMatrix, Vararg{DroppedScalar}} , subidxs:: Tuple{Any} ) =
157
- (@_propagate_inbounds_meta ; (idxs[1 ][subidxs[1 ]], tail (idxs)... ))
158
- reindex (V, idxs:: Tuple{AbstractMatrix, Vararg{DroppedScalar}} , subidxs:: Tuple{Any, Any} ) =
159
- (@_propagate_inbounds_meta ; (idxs[1 ][subidxs[1 ], subidxs[2 ]], tail (idxs)... ))
160
156
161
157
# In general, we index N-dimensional parent arrays with N indices
162
158
@generated function reindex {T,N} (V, idxs:: Tuple{AbstractArray{T,N}, Vararg{Any}} , subidxs:: Tuple{Vararg{Any}} )
163
159
if length (subidxs. parameters) >= N
164
160
subs = [:(subidxs[$ d]) for d in 1 : N]
165
161
tail = [:(subidxs[$ d]) for d in N+ 1 : length (subidxs. parameters)]
166
162
:(@_propagate_inbounds_meta ; (idxs[1 ][$ (subs... )], reindex (V, tail (idxs), ($ (tail... ),))... ))
167
- elseif length (idxs. parameters) == 1
168
- :(@_propagate_inbounds_meta ; (idxs[1 ][subidxs... ],))
169
- elseif all (T-> T<: DroppedScalar , idxs. parameters[2 : end ])
170
- :(@_propagate_inbounds_meta ; (idxs[1 ][subidxs... ], tail (idxs)... ))
171
163
else
172
- :(@_propagate_inbounds_meta ; ( merge_indexes (V, idxs, subidxs), ))
164
+ :(error ( " mismatched index dimensionalities " ))
173
165
end
174
166
end
175
167
176
168
# In general, we simply re-index the parent indices by the provided ones
177
- getindex (V :: SubArray ) = ( @_propagate_inbounds_meta ; getindex (V, 1 ))
178
- function getindex (V:: SubArray , I:: Real... )
169
+ typealias SlowSubArray{T,N,P,I} SubArray{T,N,P,I, false }
170
+ function getindex {T,N} (V:: SlowSubArray{T,N} , I:: Vararg{ Real,N} )
179
171
@_inline_meta
180
172
@boundscheck checkbounds (V, I... )
181
173
@inbounds r = V. parent[reindex (V, V. indexes, to_indexes (I... ))... ]
182
174
r
183
175
end
176
+ # Explicitly define scalar linear indexing -- this is needed so the nonscalar
177
+ # indexing methods don't take precedence here
178
+ function getindex (V:: SlowSubArray , i:: Real )
179
+ @_inline_meta
180
+ @boundscheck checkbounds (V, i)
181
+ @inbounds r = V. parent[reindex (V, V. indexes, ind2sub (size (V), to_index (i)))... ]
182
+ r
183
+ end
184
184
185
185
typealias FastSubArray{T,N,P,I} SubArray{T,N,P,I,true }
186
- getindex (V:: FastSubArray ) = (@_propagate_inbounds_meta ; getindex (V, 1 ))
187
186
function getindex (V:: FastSubArray , i:: Real )
188
187
@_inline_meta
189
188
@boundscheck checkbounds (V, i)
@@ -198,40 +197,55 @@ function getindex(V::FastContiguousSubArray, i::Real)
198
197
@inbounds r = V. parent[V. first_index + to_index (i)- 1 ]
199
198
r
200
199
end
201
- # We need this because the ::ViewIndex... method would otherwise obscure the Base fallback
202
- function getindex (V:: FastSubArray , I:: Real... )
200
+ # Just like the slow case, explicitly define scalar indexing at N dims, too
201
+ function getindex {T,N} (V:: FastSubArray{T,N} , I:: Vararg{ Real,N} )
203
202
@_inline_meta
204
203
@boundscheck checkbounds (V, I... )
205
204
@inbounds r = getindex (V, sub2ind (size (V), to_indexes (I... )... ))
206
205
r
207
206
end
208
- getindex {T,N} (V:: SubArray{T,N} , I:: ViewIndex... ) = (@_propagate_inbounds_meta ; copy (slice (V, I... )))
209
207
210
- setindex! (V:: SubArray , x) = (@_propagate_inbounds_meta ; setindex! (V, x, 1 ))
211
- function setindex! {T,N} (V:: SubArray{T,N} , x, I:: Real... )
208
+ # Nonscalar indexing just copies a view
209
+ getindex {T,N} (V:: SubArray{T,N} , i:: ViewIndex ) = (@_propagate_inbounds_meta ; copy (slice (V, i)))
210
+ getindex {T,N} (V:: SubArray{T,N} , I:: Vararg{ViewIndex,N} ) = (@_propagate_inbounds_meta ; copy (slice (V, I... )))
211
+
212
+ # Setindex is similar, but since we don't specially define non-scalar methods
213
+ # we only need to define the canonical methods. We don't need to worry about
214
+ # e.g., linear indexing for SlowSubArray since the fallbacks can do their thing
215
+ function setindex! {T,N} (V:: SlowSubArray{T,N} , x, I:: Vararg{Real,N} )
212
216
@_inline_meta
213
217
@boundscheck checkbounds (V, I... )
214
218
@inbounds V. parent[reindex (V, V. indexes, to_indexes (I... ))... ] = x
215
219
V
216
220
end
221
+ function setindex! (V:: FastSubArray , x, i:: Real )
222
+ @_inline_meta
223
+ @boundscheck checkbounds (V, i)
224
+ @inbounds V. parent[V. first_index + V. stride1* (to_index (i)- 1 )] = x
225
+ V
226
+ end
227
+ function setindex! (V:: FastContiguousSubArray , x, i:: Real )
228
+ @_inline_meta
229
+ @boundscheck checkbounds (V, i)
230
+ @inbounds V. parent[V. first_index + to_index (i)- 1 ] = x
231
+ V
232
+ end
217
233
# Nonscalar setindex! falls back to the defaults
218
234
219
- function slice {T,N} (V:: SubArray{T,N} , I:: ViewIndex... )
235
+ function unsafe_slice {T,N} (V:: SubArray{T,N} , I:: Vararg{ ViewIndex,N} )
220
236
@_inline_meta
221
- @boundscheck checkbounds (V, I... )
222
237
idxs = reindex (V, V. indexes, to_indexes (I... ))
223
238
SubArray (V. parent, idxs, index_shape (V. parent, idxs... ))
224
239
end
225
240
226
- function sub {T,N} (V:: SubArray{T,N} , I:: ViewIndex... )
241
+ function unsafe_sub {T,N} (V:: SubArray{T,N} , I:: Vararg{ ViewIndex,N} )
227
242
@_inline_meta
228
- @boundscheck checkbounds (V, I... )
229
243
idxs = reindex (V, V. indexes, keep_leading_scalars (to_indexes (I... )))
230
244
SubArray (V. parent, idxs, index_shape (V. parent, idxs... ))
231
245
end
232
246
233
- linearindexing (A :: FastSubArray ) = LinearFast ()
234
- linearindexing (A :: SubArray ) = LinearSlow ()
247
+ linearindexing {T<:FastSubArray} ( :: Type{T} ) = LinearFast ()
248
+ linearindexing {T<:SubArray} ( :: Type{T} ) = LinearSlow ()
235
249
236
250
getindex (:: Colon , i) = to_index (i)
237
251
unsafe_getindex (:: Colon , i) = to_index (i)
0 commit comments