@@ -110,9 +110,9 @@ julia> OffsetArray(a, OffsetArrays.Origin(0)) # set the origin to zero along eac
110
110
struct OffsetArray{T,N,AA<: AbstractArray{T,N} } <: AbstractArray{T,N}
111
111
parent:: AA
112
112
offsets:: NTuple{N,Int}
113
- function OffsetArray {T, N, AA} (parent:: AA , offsets:: NTuple{N, Int} ) where {T, N, AA<: AbstractArray{T,N} }
113
+ @inline function OffsetArray {T, N, AA} (parent:: AA , offsets:: NTuple{N, Int} ; checkoverflow = true ) where {T, N, AA<: AbstractArray{T,N} }
114
114
# allocation of `map` on tuple is optimized away
115
- map (overflow_check, axes (parent), offsets)
115
+ checkoverflow && map (overflow_check, axes (parent), offsets)
116
116
new {T, N, AA} (parent, offsets)
117
117
end
118
118
end
@@ -132,53 +132,40 @@ Type alias and convenience constructor for two-dimensional [`OffsetArray`](@ref)
132
132
const OffsetMatrix{T,AA<: AbstractMatrix{T} } = OffsetArray{T,2 ,AA}
133
133
134
134
# checks if the offset may be added to the range without overflowing
135
- function overflow_check (r:: AbstractUnitRange{T} , offset:: Integer ) where {T <: Integer }
136
- Base. hastypemax (T ) || return nothing
135
+ function overflow_check (r:: AbstractUnitRange , offset:: Integer )
136
+ Base. hastypemax (eltype (r) ) || return nothing
137
137
# This gives some performance boost https://github.com/JuliaLang/julia/issues/33273
138
- throw_upper_overflow_error (val) = throw (OverflowError (" offset should be <= $(typemax (T ) - val) corresponding to the axis $r , received an offset $offset " ))
139
- throw_lower_overflow_error (val) = throw (OverflowError (" offset should be >= $(typemin (T ) - val) corresponding to the axis $r , received an offset $offset " ))
138
+ throw_upper_overflow_error (val) = throw (OverflowError (" offset should be <= $(typemax (Int ) - val) corresponding to the axis $r , received an offset $offset " ))
139
+ throw_lower_overflow_error (val) = throw (OverflowError (" offset should be >= $(typemin (Int ) - val) corresponding to the axis $r , received an offset $offset " ))
140
140
141
141
# With ranges in the picture, first(r) might not necessarily be < last(r)
142
142
# we therefore use the min and max of first(r) and last(r) to check for overflow
143
143
firstlast_min, firstlast_max = minmax (first (r), last (r))
144
144
145
- if offset > 0 && firstlast_max > typemax (T ) - offset
145
+ if offset > 0 && firstlast_max > typemax (Int ) - offset
146
146
throw_upper_overflow_error (firstlast_max)
147
- elseif offset < 0 && firstlast_min < typemin (T ) - offset
147
+ elseif offset < 0 && firstlast_min < typemin (Int ) - offset
148
148
throw_lower_overflow_error (firstlast_min)
149
149
end
150
150
return nothing
151
151
end
152
- # checks if the two offsets may be added together without overflowing
153
- function overflow_check (offset_preexisting:: Integer , offset_new:: T ) where {T<: Integer }
154
- Base. hastypemax (T) || return nothing
155
- throw_upper_overflow_error () = throw (OverflowError (" offset should be <= $(typemax (eltype (offset_preexisting)) - offset_preexisting) given a pre-existing offset of $offset_preexisting , received an offset $offset_new " ))
156
- throw_lower_overflow_error () = throw (OverflowError (" offset should be >= $(typemin (eltype (offset_preexisting)) - offset_preexisting) given a pre-existing offset of $offset_preexisting , received an offset $offset_new " ))
157
-
158
- if offset_preexisting > 0 && offset_new > typemax (T) - offset_preexisting
159
- throw_upper_overflow_error ()
160
- elseif offset_preexisting < 0 && offset_new < typemin (T) - offset_preexisting
161
- throw_lower_overflow_error ()
162
- end
163
- return nothing
164
- end
165
152
166
153
# Tuples of integers are treated as offsets
167
154
# Empty Tuples are handled here
168
- @inline function OffsetArray (A:: AbstractArray , offsets:: Tuple{Vararg{Integer}} )
155
+ @inline function OffsetArray (A:: AbstractArray , offsets:: Tuple{Vararg{Integer}} ; kw ... )
169
156
_checkindices (A, offsets, " offsets" )
170
- OffsetArray {eltype(A), ndims(A), typeof(A)} (A, offsets)
157
+ OffsetArray {eltype(A), ndims(A), typeof(A)} (A, offsets; kw ... )
171
158
end
172
159
173
160
# These methods are necessary to disallow incompatible dimensions for
174
161
# the OffsetVector and the OffsetMatrix constructors
175
162
for (FT, ND) in ((:OffsetVector , :1 ), (:OffsetMatrix , :2 ))
176
- @eval @inline function $FT (A:: AbstractArray{<:Any,$ND} , offsets:: Tuple{Vararg{Integer}} )
163
+ @eval @inline function $FT (A:: AbstractArray{<:Any,$ND} , offsets:: Tuple{Vararg{Integer}} ; kw ... )
177
164
_checkindices (A, offsets, " offsets" )
178
- OffsetArray {eltype(A), $ND, typeof(A)} (A, offsets)
165
+ OffsetArray {eltype(A), $ND, typeof(A)} (A, offsets; kw ... )
179
166
end
180
167
FTstr = string (FT)
181
- @eval @inline function $FT (A:: AbstractArray , offsets:: Tuple{Vararg{Integer}} )
168
+ @eval @inline function $FT (A:: AbstractArray , offsets:: Tuple{Vararg{Integer}} ; kw ... )
182
169
throw (ArgumentError ($ FTstr* " requires a " * string ($ ND)* " D array" ))
183
170
end
184
171
end
@@ -187,95 +174,98 @@ end
187
174
for FT in (:OffsetArray , :OffsetVector , :OffsetMatrix )
188
175
# Nested OffsetArrays may strip off the wrapper and collate the offsets
189
176
# empty tuples are handled here
190
- @eval @inline function $FT (A:: OffsetArray , offsets:: Tuple{Vararg{Int}} )
177
+ @eval @inline function $FT (A:: OffsetArray , offsets:: Tuple{Vararg{Int}} ; checkoverflow = true )
191
178
_checkindices (A, offsets, " offsets" )
192
179
# ensure that the offsets may be added together without an overflow
193
- map (overflow_check, A. offsets, offsets)
194
- $ FT (parent (A), map (+ , A. offsets, offsets))
180
+ checkoverflow && map (overflow_check, axes (A), offsets)
181
+ I = map (+ , _offsets (A, parent (A)), offsets)
182
+ $ FT (parent (A), I, checkoverflow = false )
195
183
end
196
- @eval @inline function $FT (A:: OffsetArray , offsets:: Tuple{Integer,Vararg{Integer}} )
197
- $ FT (A, map (Int, offsets))
184
+ @eval @inline function $FT (A:: OffsetArray , offsets:: Tuple{Integer,Vararg{Integer}} ; kw ... )
185
+ $ FT (A, map (Int, offsets); kw ... )
198
186
end
199
187
200
188
# In general, indices get converted to AbstractUnitRanges.
201
189
# CartesianIndices{N} get converted to N ranges
202
- @eval @inline function $FT (A:: AbstractArray , inds:: Tuple{Any,Vararg{Any}} )
203
- $ FT (A, _toAbstractUnitRanges (to_indices (A, axes (A), inds)))
190
+ @eval @inline function $FT (A:: AbstractArray , inds:: Tuple{Any,Vararg{Any}} ; kw ... )
191
+ $ FT (A, _toAbstractUnitRanges (to_indices (A, axes (A), inds)); kw ... )
204
192
end
205
193
206
194
# convert ranges to offsets
207
- @eval @inline function $FT (A:: AbstractArray , inds:: Tuple{AbstractUnitRange,Vararg{AbstractUnitRange}} )
195
+ @eval @inline function $FT (A:: AbstractArray , inds:: Tuple{AbstractUnitRange,Vararg{AbstractUnitRange}} ; kw ... )
208
196
_checkindices (A, inds, " indices" )
209
197
# Performance gain by wrapping the error in a function: see https://github.com/JuliaLang/julia/issues/37558
210
198
throw_dimerr (lA, lI) = throw (DimensionMismatch (" supplied axes do not agree with the size of the array (got size $lA for the array and $lI for the indices" ))
211
199
lA = size (A)
212
200
lI = map (length, inds)
213
201
lA == lI || throw_dimerr (lA, lI)
214
- $ FT (A, map (_offset, axes (A), inds))
202
+ $ FT (A, map (_offset, axes (A), inds); kw ... )
215
203
end
216
204
217
- @eval @inline $ FT (A:: AbstractArray , inds:: Vararg ) = $ FT (A, inds)
218
- @eval @inline $ FT (A:: AbstractArray ) = $ FT (A, ntuple (zero, Val (ndims (A))))
205
+ @eval @inline $ FT (A:: AbstractArray , inds:: Vararg ; kw ... ) = $ FT (A, inds; kw ... )
206
+ @eval @inline $ FT (A:: AbstractArray ; checkoverflow = false ) = $ FT (A, ntuple (zero, Val (ndims (A))), checkoverflow = checkoverflow )
219
207
220
- @eval @inline $ FT (A:: AbstractArray , origin:: Origin ) = $ FT (A, origin (A))
208
+ @eval @inline $ FT (A:: AbstractArray , origin:: Origin ; checkoverflow = true ) = $ FT (A, origin (A); checkoverflow = checkoverflow )
221
209
end
222
210
223
211
# conversion-related methods
224
- @inline OffsetArray {T} (M:: AbstractArray , I... ) where {T} = OffsetArray {T,ndims(M)} (M, I... )
212
+ @inline OffsetArray {T} (M:: AbstractArray , I... ; kw ... ) where {T} = OffsetArray {T,ndims(M)} (M, I... ; kw ... )
225
213
226
- @inline function OffsetArray {T,N} (M:: AbstractArray{<:Any,N} , I... ) where {T,N}
214
+ @inline function OffsetArray {T,N} (M:: AbstractArray{<:Any,N} , I... ; kw ... ) where {T,N}
227
215
M2 = _of_eltype (T, M)
228
- OffsetArray {T,N,typeof(M2) } (M2, I... )
216
+ OffsetArray {T,N} (M2, I... ; kw ... )
229
217
end
218
+ @inline OffsetArray {T,N} (M:: OffsetArray{T,N} , I... ; kw... ) where {T,N} = OffsetArray (M, I... ; kw... )
219
+ @inline OffsetArray {T,N} (M:: AbstractArray{T,N} , I... ; kw... ) where {T,N} = OffsetArray {T,N,typeof(M)} (M, I... ; kw... )
230
220
231
- @inline OffsetArray {T,N,A} (M:: AbstractArray{<:Any,N} , I:: Vararg ) where {T,N,A<: AbstractArray{T,N} } = OffsetArray {T,N,A} (M, I)
232
- @inline function OffsetArray {T,N,A} (M:: AbstractArray{<:Any,N} , I:: NTuple{N,Int} ) where {T,N,A<: AbstractArray{T,N} }
233
- map (overflow_check, axes (M), I)
221
+ @inline OffsetArray {T,N,A} (M:: AbstractArray{<:Any,N} , I:: Vararg ; kw ... ) where {T,N,A<: AbstractArray{T,N} } = OffsetArray {T,N,A} (M, I; kw ... )
222
+ @inline function OffsetArray {T,N,A} (M:: AbstractArray{<:Any,N} , I:: NTuple{N,Int} ; checkoverflow = true ) where {T,N,A<: AbstractArray{T,N} }
223
+ checkoverflow && map (overflow_check, axes (M), I)
234
224
Mv = no_offset_view (M)
235
225
MvA = convert (A, Mv):: A
236
226
Iof = map (+ , _offsets (M), I)
237
- OffsetArray {T,N,A} (MvA, Iof)
227
+ OffsetArray {T,N,A} (MvA, Iof, checkoverflow = false )
238
228
end
239
- @inline function OffsetArray {T, N, AA} (parent:: AbstractArray{<:Any,N} , offsets:: NTuple{N, Integer} ) where {T, N, AA<: AbstractArray{T,N} }
240
- OffsetArray {T, N, AA} (parent, map (Int, offsets):: NTuple{N,Int} )
229
+ @inline function OffsetArray {T, N, AA} (parent:: AbstractArray{<:Any,N} , offsets:: NTuple{N, Integer} ; kw ... ) where {T, N, AA<: AbstractArray{T,N} }
230
+ OffsetArray {T, N, AA} (parent, map (Int, offsets):: NTuple{N,Int} ; kw ... )
241
231
end
242
- @inline function OffsetArray {T,N,A} (M:: AbstractArray{<:Any,N} , I:: Tuple{AbstractUnitRange,Vararg{AbstractUnitRange}} ) where {T,N,A<: AbstractArray{T,N} }
232
+ @inline function OffsetArray {T,N,A} (M:: AbstractArray{<:Any,N} , I:: Tuple{AbstractUnitRange,Vararg{AbstractUnitRange}} ; kw ... ) where {T,N,A<: AbstractArray{T,N} }
243
233
_checkindices (M, I, " indices" )
244
234
# Performance gain by wrapping the error in a function: see https://github.com/JuliaLang/julia/issues/37558
245
235
throw_dimerr (lA, lI) = throw (DimensionMismatch (" supplied axes do not agree with the size of the array (got size $lA for the array and $lI for the indices" ))
246
236
lM = size (M)
247
237
lI = map (length, I)
248
238
lM == lI || throw_dimerr (lM, lI)
249
- OffsetArray {T,N,A} (M, map (_offset, axes (M), I))
239
+ OffsetArray {T,N,A} (M, map (_offset, axes (M), I); kw ... )
250
240
end
251
- @inline function OffsetArray {T,N,A} (M:: AbstractArray{<:Any,N} , I:: Tuple ) where {T,N,A<: AbstractArray{T,N} }
252
- OffsetArray {T,N,A} (M, _toAbstractUnitRanges (to_indices (M, axes (M), I)))
241
+ @inline function OffsetArray {T,N,A} (M:: AbstractArray{<:Any,N} , I:: Tuple ; kw ... ) where {T,N,A<: AbstractArray{T,N} }
242
+ OffsetArray {T,N,A} (M, _toAbstractUnitRanges (to_indices (M, axes (M), I)); kw ... )
253
243
end
254
- @inline function OffsetArray {T,N,A} (M:: AbstractArray{<:Any,N} ) where {T,N,A<: AbstractArray{T,N} }
244
+ @inline function OffsetArray {T,N,A} (M:: AbstractArray{<:Any,N} ; kw ... ) where {T,N,A<: AbstractArray{T,N} }
255
245
Mv = no_offset_view (M)
256
246
MvA = convert (A, Mv):: A
257
- OffsetArray {T,N,A} (MvA, _offsets (M))
247
+ OffsetArray {T,N,A} (MvA, _offsets (M); kw ... )
258
248
end
259
- @inline OffsetArray {T,N,A} (M:: A ) where {T,N,A<: AbstractArray{T,N} } = OffsetArray {T,N,A} (M, ntuple (zero, Val (N)))
249
+ @inline OffsetArray {T,N,A} (M:: A ; checkoverflow = false ) where {T,N,A<: AbstractArray{T,N} } = OffsetArray {T,N,A} (M, ntuple (zero, Val (N)); checkoverflow = checkoverflow )
260
250
261
251
Base. convert (:: Type{T} , M:: AbstractArray ) where {T<: OffsetArray } = M isa T ? M : T (M)
262
252
263
253
# array initialization
264
- @inline function OffsetArray {T,N} (init:: ArrayInitializer , inds:: Tuple{Vararg{OffsetAxisKnownLength}} ) where {T,N}
254
+ @inline function OffsetArray {T,N} (init:: ArrayInitializer , inds:: Tuple{Vararg{OffsetAxisKnownLength}} ; kw ... ) where {T,N}
265
255
_checkindices (N, inds, " indices" )
266
256
AA = Array {T,N} (init, map (_indexlength, inds))
267
- OffsetArray {T, N, typeof(AA)} (AA, map (_indexoffset, inds))
257
+ OffsetArray {T, N, typeof(AA)} (AA, map (_indexoffset, inds); kw ... )
268
258
end
269
- @inline function OffsetArray {T, N} (init:: ArrayInitializer , inds:: Tuple ) where {T, N}
270
- OffsetArray {T, N} (init, _toAbstractUnitRanges (inds))
259
+ @inline function OffsetArray {T, N} (init:: ArrayInitializer , inds:: Tuple ; kw ... ) where {T, N}
260
+ OffsetArray {T, N} (init, _toAbstractUnitRanges (inds); kw ... )
271
261
end
272
- @inline OffsetArray {T,N} (init:: ArrayInitializer , inds:: Vararg ) where {T,N} = OffsetArray {T,N} (init, inds)
262
+ @inline OffsetArray {T,N} (init:: ArrayInitializer , inds:: Vararg ; kw ... ) where {T,N} = OffsetArray {T,N} (init, inds; kw ... )
273
263
274
- @inline OffsetArray {T} (init:: ArrayInitializer , inds:: NTuple{N, OffsetAxisKnownLength} ) where {T,N} = OffsetArray {T,N} (init, inds)
275
- @inline function OffsetArray {T} (init:: ArrayInitializer , inds:: Tuple ) where {T}
276
- OffsetArray {T} (init, _toAbstractUnitRanges (inds))
264
+ @inline OffsetArray {T} (init:: ArrayInitializer , inds:: NTuple{N, OffsetAxisKnownLength} ; kw ... ) where {T,N} = OffsetArray {T,N} (init, inds; kw ... )
265
+ @inline function OffsetArray {T} (init:: ArrayInitializer , inds:: Tuple ; kw ... ) where {T}
266
+ OffsetArray {T} (init, _toAbstractUnitRanges (inds); kw ... )
277
267
end
278
- @inline OffsetArray {T} (init:: ArrayInitializer , inds:: Vararg ) where {T} = OffsetArray {T} (init, inds)
268
+ @inline OffsetArray {T} (init:: ArrayInitializer , inds:: Vararg ; kw ... ) where {T} = OffsetArray {T} (init, inds; kw ... )
279
269
280
270
Base. IndexStyle (:: Type{OA} ) where {OA<: OffsetArray } = IndexStyle (parenttype (OA))
281
271
parenttype (:: Type{OffsetArray{T,N,AA}} ) where {T,N,AA} = AA
308
298
309
299
# Utils to translate a function to the parent while preserving offsets
310
300
unwrap (x) = x, identity
311
- unwrap (x:: OffsetArray ) = parent (x), data -> OffsetArray (data, x. offsets)
301
+ unwrap (x:: OffsetArray ) = parent (x), data -> OffsetArray (data, x. offsets, checkoverflow = false )
312
302
function parent_call (f, x)
313
303
parent, wrap_offset = unwrap (x)
314
304
wrap_offset (f (parent))
469
459
# An OffsetUnitRange might use the rapid getindex(::Array, ::AbstractUnitRange{Int}) for contiguous indexing
470
460
@propagate_inbounds function Base. getindex (A:: Array , r:: OffsetUnitRange{Int} )
471
461
B = A[_contiguousindexingtype (parent (r))]
472
- OffsetArray (B, axes (r))
462
+ OffsetArray (B, axes (r), checkoverflow = false )
473
463
end
474
464
475
465
# avoid hitting the slow method getindex(::Array, ::AbstractRange{Int})
0 commit comments