Skip to content

Commit

Permalink
getindex(::Array, ::OffsetUnitRange)
Browse files Browse the repository at this point in the history
  • Loading branch information
jishnub committed Feb 28, 2021
1 parent 21956e7 commit 72a5eaf
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 14 deletions.
27 changes: 22 additions & 5 deletions benchmark/benchmarks.jl
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ y = OffsetArray{Float64}(undef, -dim + 1 : dim);
x2d = Array{Float64}(undef, 2*dim, 2*dim);
y2d = OffsetArray{Float64}(undef, -dim + 1 : dim, -dim + 1 : dim);

r = OffsetVector(1:dim, 0);
s = OffsetVector(1:dim, 0);
sur = 1:dim;
sior = OffsetArrays.IdOffsetRange(parent(s));

fill1d(x) = for i in axes(x,1); x[i] = i; end
fill2d(x) = for j in axes(x,2); for i in axes(x,1); x[i,j] = i + j; end; end
Expand Down Expand Up @@ -58,8 +59,24 @@ end

# Benchmarks of vector indexing using OffsetRanges as axes
@showbenchmark vectorlinearindexing(x, s)
@showbenchmark vectorlinearindexing(x, parent(s))
@showbenchmark vectorlinearindexing(x, sur)
@showbenchmark vectorlinearindexing(y, s)
@showbenchmark vectorlinearindexing(y, sur)

@showbenchmark vectorlinearindexing(sur, s)
@showbenchmark vectorlinearindexing(sur, sur)

@showbenchmark vectorCartesianindexing(x2d, s, s)
@showbenchmark vectorCartesianindexing(x2d, parent(s), parent(s))
@showbenchmark nestedvectorlinearindexing(x, r, s)
@showbenchmark nestedvectorlinearindexing(x, parent(r), parent(s))
@showbenchmark vectorCartesianindexing(x2d, sur, sur)

@showbenchmark nestedvectorlinearindexing(x, s, s)
@showbenchmark nestedvectorlinearindexing(x, sur, sur)
@showbenchmark nestedvectorlinearindexing(x, s, sior)
@showbenchmark nestedvectorlinearindexing(x, sur, sior)
@showbenchmark nestedvectorlinearindexing(x, sior, sior)
@showbenchmark vectorlinearindexing(x, sior[sior])
@showbenchmark nestedvectorlinearindexing(x, sur, sior)
@showbenchmark vectorlinearindexing(x, sur[sior])
@showbenchmark nestedvectorlinearindexing(x, sior, sur)
@showbenchmark vectorlinearindexing(x, sior[sur])
@showbenchmark nestedvectorlinearindexing(x, sur, sur)
42 changes: 33 additions & 9 deletions src/OffsetArrays.jl
Original file line number Diff line number Diff line change
Expand Up @@ -344,31 +344,55 @@ Base.checkindex(::Type{Bool}, inds::AbstractUnitRange, or::OffsetRange) = Base.c
@inline function Base.getindex(a::OffsetRange, r::OffsetRange)
@boundscheck checkbounds(a, r)
@inbounds pr = a.parent[r.parent .- a.offsets[1]]
OffsetArray(pr, axes(r,1))
_maybewrapoffset(pr, axes(r,1))
end
@inline function Base.getindex(a::OffsetRange, r::IdOffsetRange)
@boundscheck checkbounds(a, r)
@inbounds pr = a.parent[r.parent .+ (r.offset - a.offsets[1])]
OffsetArray(pr, axes(r,1))
_maybewrapoffset(pr, axes(r,1))
end
@inline function Base.getindex(a::OffsetRange, r::AbstractRange)
@boundscheck checkbounds(a, r)
@inbounds pr = a.parent[r .- a.offsets[1]]
OffsetArray(pr, axes(r,1))
_maybewrapoffset(pr, axes(r,1))
end
@inline function Base.getindex(a::AbstractRange, r::OffsetRange)
@boundscheck checkbounds(a, r)
@inbounds pr = a[parent(r)]
OffsetArray(pr, axes(r,1))
@propagate_inbounds function Base.getindex(a::AbstractRange, r::OffsetRange)
pr = a[parent(r)]
_maybewrapoffset(pr, axes(r,1))
end

# An OffsetUnitRange might use the rapid getindex(::Array, ::UnitRange{Int}) for contiguous indexing
@propagate_inbounds function Base.getindex(A::Array, or::OffsetUnitRange{Int})
pr = A[UnitRange(parent(or))]
OffsetArray(pr, axes(or))
end
@inline function Base.getindex(A::OffsetArray{<:Any,<:Any,<:Array}, or::OffsetUnitRange{Int})
@boundscheck checkbounds(A, or)
@inbounds Ap = parent(A)[UnitRange(parent(or))]
OffsetArray(Ap, axes(or))
end

# avoid hitting the slow method getindex(::Array, ::AbstractRange{Int})
# instead use the faster getindex(::Array, ::UnitRange{Int})
@propagate_inbounds function Base.getindex(A::Array, ior::IdOffsetRange{Int})
pr = A[UnitRange(ior)]
OffsetArray(pr, axes(ior))
end
@inline function Base.getindex(A::OffsetArray{<:Any,<:Any,<:Array}, ior::IdOffsetRange{Int})
@boundscheck checkbounds(A, ior)
@inbounds Ap = parent(A)[UnitRange(ior)]
OffsetArray(Ap, axes(ior))
end

# An OffsetUnitRange{<:Integer} has an equivalent IdOffsetRange with the same values and axes
# We may replace the former with the latter in an indexing operation to obtain a performance boost
@inline function Base.to_indices(A::AbstractArray, ax::Tuple, I::Tuple{OffsetUnitRange{<:Integer}, Vararg{Any}})
or = first(I)
r = parent(or)
of = or.offsets[1]
ior = IdOffsetRange(UnitRange(r) .- of, of)
of = first(axes(or,1)) - 1
# UnitRange(a - of, b - of) is a simpler operation than UnitRange(a, b) .- of
# This might permit compiler optimizations
ior = IdOffsetRange(UnitRange(first(r) - of, last(r) - of), of)
to_indices(A, ax, (ior, tail(I)...))
end

Expand Down
2 changes: 2 additions & 0 deletions src/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ end
@inline _maybewrapoffset(r::AbstractVector, ::Base.OneTo) = no_offset_view(r)
@inline function _maybewrapoffset(r::AbstractUnitRange{<:Integer}, ax)
of = first(ax) - 1
# UnitRange(a - of, b - of) is a simpler operation than UnitRange(a, b) .- of
# This might permit compiler optimizations
IdOffsetRange(UnitRange(first(r) - of, last(r) - of), of)
end
@inline _maybewrapoffset(r::AbstractVector, ax) = OffsetArray(r, ax)
8 changes: 8 additions & 0 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -819,6 +819,10 @@ end

for r1 in Any[
# AbstractArrays
ones(100),
ones(-1:100),

# OffsetRanges
OffsetArray(10:1000, 0), # 1-based index
OffsetArray(UnitRange(10.0, 1000.0), 0), # 1-based index
OffsetArray(10:3:1000, 3), # offset index
Expand Down Expand Up @@ -933,6 +937,10 @@ end

for r1 in Any[
# AbstractArrays
ones(100),
ones(-1:100),

# OffsetRanges
OffsetArray(10:1000, 0), # 1-based index
OffsetArray(UnitRange(10.0, 1000.0), 0), # 1-based index
OffsetArray(10:1000, 3), # offset index
Expand Down

0 comments on commit 72a5eaf

Please sign in to comment.