@@ -167,6 +167,7 @@ offset_coerce(::Type{I}, r::AbstractUnitRange) where I<:AbstractUnitRange =
167
167
@inline Base. axes1 (r:: IdOffsetRange ) = IdOffsetRange (Base. axes1 (r. parent), r. offset)
168
168
@inline Base. unsafe_indices (r:: IdOffsetRange ) = (Base. axes1 (r),)
169
169
@inline Base. length (r:: IdOffsetRange ) = length (r. parent)
170
+ @inline Base. isempty (r:: IdOffsetRange ) = isempty (r. parent)
170
171
Base. reduced_index (i:: IdOffsetRange ) = typeof (i)(first (i): first (i))
171
172
# Workaround for #92 on Julia < 1.4
172
173
Base. reduced_index (i:: IdentityUnitRange{<:IdOffsetRange} ) = typeof (i)(first (i): first (i))
@@ -178,16 +179,23 @@ for f in [:first, :last]
178
179
@eval @inline Base.$ f (r:: IdOffsetRange ) = eltype (r)($ f (r. parent) + r. offset)
179
180
end
180
181
181
- @inline function Base . iterate (r :: IdOffsetRange )
182
- ret = iterate (r . parent )
183
- ret === nothing && return nothing
184
- return ( eltype (r)(ret[ 1 ] + r . offset), ret[ 2 ])
185
- end
186
- @inline function Base . iterate (r:: IdOffsetRange , i)
187
- ret = iterate (r. parent, i)
182
+ # Iteration for an IdOffsetRange
183
+ @inline Base . iterate (r :: IdOffsetRange , i ... ) = _iterate (r, i ... )
184
+ # In general we iterate over the parent term by term and add the offset.
185
+ # This might have some performance degradation when coupled with bounds-checking
186
+ # See https://github.com/JuliaArrays/OffsetArrays.jl/issues/214
187
+ @inline function _iterate (r:: IdOffsetRange , i... )
188
+ ret = iterate (r. parent, i... )
188
189
ret === nothing && return nothing
189
190
return (eltype (r)(ret[1 ] + r. offset), ret[2 ])
190
191
end
192
+ # Base.OneTo(n) is known to be exactly equivalent to the range 1:n,
193
+ # and has no specialized iteration defined for it,
194
+ # so we may add the offset to the range directly and iterate over the result
195
+ # This gets around the performance issue described in issue #214
196
+ # We use the helper function _addoffset to evaluate the range instead of broadcasting
197
+ # just in case this makes it easy for the compiler.
198
+ @inline _iterate (r:: IdOffsetRange{<:Integer, <:Base.OneTo} , i... ) = iterate (_addoffset (r. parent, r. offset), i... )
191
199
192
200
@inline function Base. getindex (r:: IdOffsetRange , i:: Integer )
193
201
i isa Bool && throw (ArgumentError (" invalid index: $i of type Bool" ))
0 commit comments