@@ -167,6 +167,7 @@ offset_coerce(::Type{I}, r::AbstractUnitRange) where I<:AbstractUnitRange =
167167@inline Base. axes1 (r:: IdOffsetRange ) = IdOffsetRange (Base. axes1 (r. parent), r. offset)
168168@inline Base. unsafe_indices (r:: IdOffsetRange ) = (Base. axes1 (r),)
169169@inline Base. length (r:: IdOffsetRange ) = length (r. parent)
170+ @inline Base. isempty (r:: IdOffsetRange ) = isempty (r. parent)
170171Base. reduced_index (i:: IdOffsetRange ) = typeof (i)(first (i): first (i))
171172# Workaround for #92 on Julia < 1.4
172173Base. reduced_index (i:: IdentityUnitRange{<:IdOffsetRange} ) = typeof (i)(first (i): first (i))
@@ -178,16 +179,23 @@ for f in [:first, :last]
178179 @eval @inline Base.$ f (r:: IdOffsetRange ) = eltype (r)($ f (r. parent) + r. offset)
179180end
180181
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... )
188189 ret === nothing && return nothing
189190 return (eltype (r)(ret[1 ] + r. offset), ret[2 ])
190191end
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... )
191199
192200@inline function Base. getindex (r:: IdOffsetRange , i:: Integer )
193201 i isa Bool && throw (ArgumentError (" invalid index: $i of type Bool" ))
0 commit comments