Skip to content

Commit f245c6a

Browse files
committed
Support size, length, atsign-inbounds
This is now permitted due to JuliaLang/julia#24899
1 parent cc0ae52 commit f245c6a

File tree

3 files changed

+38
-111
lines changed

3 files changed

+38
-111
lines changed

REQUIRE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
julia 0.7.0-beta.73
1+
julia 0.7.0-beta.270

src/OffsetArrays.jl

Lines changed: 20 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ __precompile__()
22

33
module OffsetArrays
44

5-
using Base: Indices, tail
5+
using Base: Indices, tail, @propagate_inbounds
66

7-
export OffsetArray, OffsetVector, @unsafe
7+
export OffsetArray, OffsetVector
88

99
struct OffsetArray{T,N,AA<:AbstractArray} <: AbstractArray{T,N}
1010
parent::AA
@@ -58,12 +58,12 @@ parenttype(A::OffsetArray) = parenttype(typeof(A))
5858

5959
Base.parent(A::OffsetArray) = A.parent
6060

61-
errmsg(A) = error("size not supported for arrays with axes $(axes(A)); see http://docs.julialang.org/en/latest/devdocs/offset-arrays/")
62-
Base.size(A::OffsetArray) = errmsg(A)
63-
Base.size(A::OffsetArray, d) = errmsg(A)
6461
Base.eachindex(::IndexCartesian, A::OffsetArray) = CartesianIndices(axes(A))
6562
Base.eachindex(::IndexLinear, A::OffsetVector) = axes(A, 1)
6663

64+
Base.size(A::OffsetArray) = size(parent(A))
65+
Base.size(A::OffsetArray, d) = size(parent(A), d)
66+
6767
# Implementations of axes and indices1. Since bounds-checking is
6868
# performance-critical and relies on axes, these are usually worth
6969
# optimizing thoroughly.
@@ -74,8 +74,7 @@ Base.eachindex(::IndexLinear, A::OffsetVector) = axes(A, 1)
7474
@inline _axes(inds, offsets) =
7575
(Base.Slice(inds[1] .+ offsets[1]), _axes(tail(inds), tail(offsets))...)
7676
_axes(::Tuple{}, ::Tuple{}) = ()
77-
Base.indices1(A::OffsetArray{T,0}) where {T} = 1:1 # we only need to specialize this one
78-
77+
Base.axes1(A::OffsetArray{T,0}) where {T} = 1:1 # we only need to specialize this one
7978

8079
const OffsetAxis = Union{Integer, UnitRange, Base.Slice{<:UnitRange}, Base.OneTo}
8180
function Base.similar(A::OffsetArray, ::Type{T}, dims::Dims) where T
@@ -111,34 +110,33 @@ Base.trues(inds::NTuple{N, Union{Integer, AbstractUnitRange}}) where {N} =
111110
Base.falses(inds::NTuple{N, Union{Integer, AbstractUnitRange}}) where {N} =
112111
fill!(OffsetArray(BitArray{N}(undef, map(indexlength, inds)), map(indexoffset, inds)), false)
113112

114-
# Don't allow bounds-checks to be removed during Julia 0.5
115-
@inline function Base.getindex(A::OffsetArray{T,N}, I::Vararg{Int,N}) where {T,N}
116-
checkbounds(A, I...)
113+
@inline @propagate_inbounds function Base.getindex(A::OffsetArray{T,N}, I::Vararg{Int,N}) where {T,N}
114+
@boundscheck checkbounds(A, I...)
117115
@inbounds ret = parent(A)[offset(A.offsets, I)...]
118116
ret
119117
end
120-
@inline function Base.getindex(A::OffsetVector, i::Int)
121-
checkbounds(A, i)
118+
@inline @propagate_inbounds function Base.getindex(A::OffsetVector, i::Int)
119+
@boundscheck checkbounds(A, i)
122120
@inbounds ret = parent(A)[offset(A.offsets, (i,))[1]]
123121
ret
124122
end
125-
@inline function Base.getindex(A::OffsetArray, i::Int)
126-
checkbounds(A, i)
123+
@inline @propagate_inbounds function Base.getindex(A::OffsetArray, i::Int)
124+
@boundscheck checkbounds(A, i)
127125
@inbounds ret = parent(A)[i]
128126
ret
129127
end
130-
@inline function Base.setindex!(A::OffsetArray{T,N}, val, I::Vararg{Int,N}) where {T,N}
131-
checkbounds(A, I...)
128+
@inline @propagate_inbounds function Base.setindex!(A::OffsetArray{T,N}, val, I::Vararg{Int,N}) where {T,N}
129+
@boundscheck checkbounds(A, I...)
132130
@inbounds parent(A)[offset(A.offsets, I)...] = val
133131
val
134132
end
135-
@inline function Base.setindex!(A::OffsetVector, val, i::Int)
136-
checkbounds(A, i)
133+
@inline @propagate_inbounds function Base.setindex!(A::OffsetVector, val, i::Int)
134+
@boundscheck checkbounds(A, i)
137135
@inbounds parent(A)[offset(A.offsets, (i,))[1]] = val
138136
val
139137
end
140-
@inline function Base.setindex!(A::OffsetArray, val, i::Int)
141-
checkbounds(A, i)
138+
@inline @propagate_inbounds function Base.setindex!(A::OffsetArray, val, i::Int)
139+
@boundscheck checkbounds(A, i)
142140
@inbounds parent(A)[i] = val
143141
val
144142
end
@@ -163,82 +161,10 @@ offset(offsets::Tuple{Vararg{Int}}, inds::Tuple{}) = error("inds cannot be short
163161

164162
indexoffset(r::AbstractRange) = first(r) - 1
165163
indexoffset(i::Integer) = 0
166-
indexlength(r::AbstractRange) = Base._length(r)
164+
indexlength(r::AbstractRange) = length(r)
167165
indexlength(i::Integer) = i
168166

169-
macro unsafe(ex)
170-
esc(unsafe(ex))
171-
end
172-
unsafe(ex) = ex
173-
function unsafe(ex::Expr)
174-
if ex.head (:+=, :-=, :*=, :/=)
175-
ex = Expr(:(=), ex.args[1], Expr(:call, Symbol(string(ex.head)[1]), ex.args...))
176-
end
177-
if ex.head == :(=)
178-
a = ex.args[1]
179-
if isa(a, Expr) && (a::Expr).head == :ref
180-
# setindex!
181-
newargs = map(unsafe, ex.args[2:end])
182-
@assert length(newargs) == 1
183-
return Expr(:call, :(OffsetArrays.unsafe_setindex!), (a::Expr).args[1], newargs[1], (a::Expr).args[2:end]...)
184-
end
185-
end
186-
newargs = map(unsafe, ex.args)
187-
if ex.head == :ref
188-
# getindex
189-
return Expr(:call, :(OffsetArrays.unsafe_getindex), newargs...)
190-
end
191-
Expr(ex.head, newargs...)
192-
end
193-
194-
@inline unsafe_getindex(a::AbstractArray, I...) = (@inbounds ret = a[I...]; ret)
195-
@inline unsafe_setindex!(a::AbstractArray, val, I...) = (@inbounds a[I...] = val; val)
196-
197-
# Linear indexing
198-
@inline unsafe_getindex(a::OffsetArray, i::Int) = _unsafe_getindex(IndexStyle(a), a, i)
199-
@inline unsafe_setindex!(a::OffsetArray, val, i::Int) = _unsafe_setindex!(IndexStyle(a), a, val, i)
200-
for T in (IndexLinear, IndexCartesian) # ambiguity-resolution requires specificity for both
201-
@eval begin
202-
@inline function _unsafe_getindex(::$T, a::OffsetVector, i::Int)
203-
@inbounds ret = parent(a)[offset(a.offsets, (i,))[1]]
204-
ret
205-
end
206-
@inline function _unsafe_setindex!(::$T, a::OffsetVector, val, i::Int)
207-
@inbounds parent(a)[offset(a.offsets, (i,))[1]] = val
208-
val
209-
end
210-
end
211-
end
212-
@inline function _unsafe_getindex(::IndexLinear, a::OffsetArray, i::Int)
213-
@inbounds ret = parent(a)[i]
214-
ret
215-
end
216-
@inline _unsafe_getindex(::IndexCartesian, a::OffsetArray, i::Int) =
217-
unsafe_getindex(a, CartesianIndices(axes(a))[i])
218-
@inline function _unsafe_setindex!(::IndexLinear, a::OffsetArray, val, i::Int)
219-
@inbounds parent(a)[i] = val
220-
val
221-
end
222-
@inline _unsafe_setindex!(::IndexCartesian, a::OffsetArray, val, i::Int) =
223-
unsafe_setindex!(a, val, CartesianIndices(axes(a))[i]...)
224-
225-
@inline unsafe_getindex(a::OffsetArray, I::Int...) = unsafe_getindex(parent(a), offset(a.offsets, I)...)
226-
@inline unsafe_setindex!(a::OffsetArray, val, I::Int...) = unsafe_setindex!(parent(a), val, offset(a.offsets, I)...)
227-
@inline unsafe_getindex(a::OffsetArray, I...) = unsafe_getindex(a, Base.IteratorsMD.flatten(I)...)
228-
@inline unsafe_setindex!(a::OffsetArray, val, I...) = unsafe_setindex!(a, val, Base.IteratorsMD.flatten(I)...)
229-
230-
# Indexing a SubArray which has OffsetArray axes
231-
OffsetSubArray{T,N,P,I<:Tuple{OffsetArray,Vararg{OffsetArray}}} = SubArray{T,N,P,I,false}
232-
@inline function unsafe_getindex(a::OffsetSubArray{T,N}, I::Vararg{Int,N}) where {T,N}
233-
J = map(unsafe_getindex, a.indexes, I)
234-
unsafe_getindex(parent(a), J...)
235-
end
236-
@inline function unsafe_setindex!(a::OffsetSubArray{T,N}, val, I::Vararg{Int,N}) where {T,N}
237-
J = map(unsafe_getindex, a.indexes, I)
238-
unsafe_setindex!(parent(a), val, J...)
239-
end
240-
@inline unsafe_getindex(a::OffsetSubArray, I::Union{Integer,CartesianIndex}...) = unsafe_getindex(a, Base.IteratorsMD.flatten(I)...)
241-
@inline unsafe_setindex!(a::OffsetSubArray, val, I::Union{Integer,CartesianIndex}...) = unsafe_setindex!(a, val, Base.IteratorsMD.flatten(I)...)
167+
@eval @deprecate $(Symbol("@unsafe")) $(Symbol("@inbounds"))
242168

243169
function Base.showarg(io::IO, a::OffsetArray, toplevel)
244170
print(io, "OffsetArray(")

test/runtests.jl

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ using DelimitedFiles
66

77
# Basics
88
for n = 0:5
9-
for a in (OffsetArray(ones(Int,ntuple(d->1,n)), ntuple(x->x-1,n)),
9+
for z in (OffsetArray(ones(Int,ntuple(d->1,n)), ntuple(x->x-1,n)),
1010
fill!(OffsetArray{Float64}(undef, ntuple(x->x:x, n)), 1),
1111
fill!(OffsetArray{Float64}(undef, ntuple(x->x:x, n)...), 1),
1212
fill!(OffsetArray{Float64,n}(undef, ntuple(x->x:x, n)), 1),
1313
fill!(OffsetArray{Float64,n}(undef, ntuple(x->x:x, n)...), 1))
14-
@test length(LinearIndices(a)) == 1
15-
@test axes(a) == ntuple(x->x:x, n)
16-
@test a[1] == 1
14+
@test length(LinearIndices(z)) == 1
15+
@test axes(z) == ntuple(x->x:x, n)
16+
@test z[1] == 1
1717
end
1818
end
1919
a0 = reshape([3])
@@ -41,8 +41,9 @@ A0 = [1 3; 2 4]
4141
A = OffsetArray(A0, (-1,2)) # IndexLinear
4242
S = OffsetArray(view(A0, 1:2, 1:2), (-1,2)) # IndexCartesian
4343
@test axes(A) == axes(S) == (0:1, 3:4)
44-
@test_throws ErrorException size(A)
45-
@test_throws ErrorException size(A, 1)
44+
@test size(A) == size(A0)
45+
@test size(A, 1) == size(A0, 1)
46+
@test length(A) == length(A0)
4647
@test A == OffsetArray(A0, 0:1, 3:4)
4748
@test_throws DimensionMismatch OffsetArray(A0, 0:2, 3:4)
4849
@test_throws DimensionMismatch OffsetArray(A0, 0:1, 2:4)
@@ -52,10 +53,10 @@ S = OffsetArray(view(A0, 1:2, 1:2), (-1,2)) # IndexCartesian
5253
@test A[1,3] == A[1,3,1] == A[2] == S[1,3] == S[1,3,1] == S[2] == 2
5354
@test A[0,4] == A[0,4,1] == A[3] == S[0,4] == S[0,4,1] == S[3] == 3
5455
@test A[1,4] == A[1,4,1] == A[4] == S[1,4] == S[1,4,1] == S[4] == 4
55-
@test @unsafe(A[0,3]) == @unsafe(A[0,3,1]) == @unsafe(A[1]) == @unsafe(S[0,3]) == @unsafe(S[0,3,1]) == @unsafe(S[1]) == 1
56-
@test @unsafe(A[1,3]) == @unsafe(A[1,3,1]) == @unsafe(A[2]) == @unsafe(S[1,3]) == @unsafe(S[1,3,1]) == @unsafe(S[2]) == 2
57-
@test @unsafe(A[0,4]) == @unsafe(A[0,4,1]) == @unsafe(A[3]) == @unsafe(S[0,4]) == @unsafe(S[0,4,1]) == @unsafe(S[3]) == 3
58-
@test @unsafe(A[1,4]) == @unsafe(A[1,4,1]) == @unsafe(A[4]) == @unsafe(S[1,4]) == @unsafe(S[1,4,1]) == @unsafe(S[4]) == 4
56+
@test @inbounds(A[0,3]) == @inbounds(A[0,3,1]) == @inbounds(A[1]) == @inbounds(S[0,3]) == @inbounds(S[0,3,1]) == @inbounds(S[1]) == 1
57+
@test @inbounds(A[1,3]) == @inbounds(A[1,3,1]) == @inbounds(A[2]) == @inbounds(S[1,3]) == @inbounds(S[1,3,1]) == @inbounds(S[2]) == 2
58+
@test @inbounds(A[0,4]) == @inbounds(A[0,4,1]) == @inbounds(A[3]) == @inbounds(S[0,4]) == @inbounds(S[0,4,1]) == @inbounds(S[3]) == 3
59+
@test @inbounds(A[1,4]) == @inbounds(A[1,4,1]) == @inbounds(A[4]) == @inbounds(S[1,4]) == @inbounds(S[1,4,1]) == @inbounds(S[4]) == 4
5960
@test_throws BoundsError A[1,1]
6061
@test_throws BoundsError S[1,1]
6162
@test_throws BoundsError A[0,3,2]
@@ -65,7 +66,7 @@ Ac[0,3] = 10
6566
@test Ac[0,3] == 10
6667
Ac[0,3,1] = 11
6768
@test Ac[0,3] == 11
68-
@unsafe Ac[0,3,1] = 12
69+
@inbounds Ac[0,3,1] = 12
6970
@test Ac[0,3] == 12
7071

7172
# Vector indexing
@@ -86,8 +87,8 @@ Ac[0,3,1] = 11
8687
# CartesianIndexing
8788
@test A[CartesianIndex((0,3))] == S[CartesianIndex((0,3))] == 1
8889
@test A[CartesianIndex((0,3)),1] == S[CartesianIndex((0,3)),1] == 1
89-
@test @unsafe(A[CartesianIndex((0,3))]) == @unsafe(S[CartesianIndex((0,3))]) == 1
90-
@test @unsafe(A[CartesianIndex((0,3)),1]) == @unsafe(S[CartesianIndex((0,3)),1]) == 1
90+
@test @inbounds(A[CartesianIndex((0,3))]) == @inbounds(S[CartesianIndex((0,3))]) == 1
91+
@test @inbounds(A[CartesianIndex((0,3)),1]) == @inbounds(S[CartesianIndex((0,3)),1]) == 1
9192
@test_throws BoundsError A[CartesianIndex(1,1)]
9293
@test_throws BoundsError A[CartesianIndex(1,1),0]
9394
@test_throws BoundsError A[CartesianIndex(1,1),2]
@@ -353,12 +354,12 @@ B = fill(5, 1:3, -1:1)
353354
@test axes(B) == (1:3,-1:1)
354355
@test all(B.==5)
355356

356-
# @unsafe
357+
# @inbounds
357358
a = OffsetArray(zeros(7), -3:3)
358-
unsafe_fill!(x) = @unsafe(for i in axes(x,1); x[i] = i; end)
359+
unsafe_fill!(x) = @inbounds(for i in axes(x,1); x[i] = i; end)
359360
function unsafe_sum(x)
360361
s = zero(eltype(x))
361-
@unsafe for i in axes(x,1)
362+
@inbounds for i in axes(x,1)
362363
s += x[i]
363364
end
364365
s

0 commit comments

Comments
 (0)