Skip to content

Commit 6418ba4

Browse files
authored
Merge pull request #10 from alsam/teh/unsafe
Add unsafe macro to eliminate bounds checking
2 parents 7bfee1f + dc46b94 commit 6418ba4

File tree

3 files changed

+69
-3
lines changed

3 files changed

+69
-3
lines changed

benchmark/benchmarks.jl

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,17 @@ x2d = Array(Float64, 2*dim, 2*dim)
99
y2d = OffsetArray(Float64, -dim + 1 : dim, -dim + 1 : dim)
1010

1111
fill(x) = for i in indices(x,1); x[i] = i; end
12-
fill2d(x) = for i in indices(x,1); for j in indices(x,2); x[i,j] = i + j; end; end
12+
fill2d(x) = for j in indices(x,2); for i in indices(x,1); x[i,j] = i + j; end; end
1313
update(x) = for i in indices(x,1); x[i] = x[i] + i; end
14-
update2d(x) = for i in indices(x,1); for j in indices(x,2); x[i,j] = x[i,j] + i + j; end; end
14+
update2d(x) = for j in indices(x,2); for i in indices(x,1); x[i,j] = x[i,j] + i + j; end; end
1515
update_eachindex(x) = for i in eachindex(x); x[i] = x[i] + i; end
1616

17+
unsafe_fill(x) = @unsafe(for i in indices(x,1); x[i] = i; end)
18+
unsafe_fill2d(x) = @unsafe(for j in indices(x,2); for i in indices(x,1); x[i,j] = i + j; end; end)
19+
unsafe_update(x) = @unsafe(for i in indices(x,1); x[i] = x[i] + i; end)
20+
unsafe_update2d(x) = @unsafe(for j in indices(x,2); for i in indices(x,1); x[i,j] = x[i,j] + i + j; end; end)
21+
unsafe_update_eachindex(x) = @unsafe(for i in eachindex(x); x[i] = x[i] + i; end)
22+
1723
@show @benchmark fill(x)
1824
@show @benchmark fill(y)
1925
@show @benchmark fill2d(x2d)
@@ -24,3 +30,14 @@ update_eachindex(x) = for i in eachindex(x); x[i] = x[i] + i; end
2430
@show @benchmark update2d(y2d)
2531
@show @benchmark update_eachindex(x)
2632
@show @benchmark update_eachindex(y)
33+
34+
@show @benchmark unsafe_fill(x)
35+
@show @benchmark unsafe_fill(y)
36+
@show @benchmark unsafe_fill2d(x2d)
37+
@show @benchmark unsafe_fill2d(y2d)
38+
@show @benchmark unsafe_update(x)
39+
@show @benchmark unsafe_update(y)
40+
@show @benchmark unsafe_update2d(x2d)
41+
@show @benchmark unsafe_update2d(y2d)
42+
@show @benchmark unsafe_update_eachindex(x)
43+
@show @benchmark unsafe_update_eachindex(y)

src/OffsetArrays.jl

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ Base.@deprecate_binding (..) Colon()
66

77
using Base: Indices, LinearSlow, LinearFast, tail
88

9-
export OffsetArray
9+
export OffsetArray, @unsafe
1010

1111
immutable OffsetArray{T,N,AA<:AbstractArray} <: AbstractArray{T,N}
1212
parent::AA
@@ -128,4 +128,37 @@ _offset(out, ::Tuple{}, ::Tuple{}) = out
128128
indexoffset(r::Range) = first(r) - 1
129129
indexoffset(i::Integer) = 0
130130

131+
macro unsafe(ex)
132+
esc(unsafe(ex))
133+
end
134+
unsafe(ex) = ex
135+
function unsafe(ex::Expr)
136+
if ex.head (:+=, :-=, :*=, :/=)
137+
ex = Expr(:(=), ex.args[1], Expr(:call, Symbol(string(ex.head)[1]), ex.args...))
138+
end
139+
if ex.head == :(=)
140+
a = ex.args[1]
141+
if isa(a, Expr) && (a::Expr).head == :ref
142+
# setindex!
143+
newargs = map(unsafe, ex.args[2:end])
144+
@assert length(newargs) == 1
145+
return Expr(:call, :(OffsetArrays.unsafe_setindex!), (a::Expr).args[1], newargs[1], (a::Expr).args[2:end]...)
146+
end
147+
end
148+
newargs = map(unsafe, ex.args)
149+
if ex.head == :ref
150+
# getindex
151+
return Expr(:call, :(OffsetArrays.unsafe_getindex), newargs...)
152+
end
153+
Expr(ex.head, newargs...)
154+
end
155+
156+
@inline unsafe_getindex(a::AbstractArray, I...) = (@inbounds ret = a[I...]; ret)
157+
@inline unsafe_setindex!(a::AbstractArray, val, I...) = (@inbounds a[I...] = val; val)
158+
159+
@inline unsafe_getindex(a::OffsetArray, I::Int...) = (@inbounds ret = parent(a)[offset(a.offsets, I)...]; ret)
160+
@inline unsafe_setindex!(a::OffsetArray, val, I::Int...) = (@inbounds parent(a)[offset(a.offsets, I)...] = val; val)
161+
@inline unsafe_getindex(a::OffsetArray, I...) = unsafe_getindex(a, Base.IteratorsMD.flatten(I)...)
162+
@inline unsafe_setindex!(a::OffsetArray, val, I...) = unsafe_setindex!(a, val, Base.IteratorsMD.flatten(I)...)
163+
131164
end # module

test/runtests.jl

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,3 +323,19 @@ B = ones(1:3, -1:1)
323323
B = fill(5, 1:3, -1:1)
324324
@test indices(B) == (1:3,-1:1)
325325
@test all(B.==5)
326+
327+
# @unsafe
328+
a = OffsetArray(zeros(7), -3:3)
329+
unsafe_fill!(x) = @unsafe(for i in indices(x,1); x[i] = i; end)
330+
function unsafe_sum(x)
331+
s = zero(eltype(x))
332+
@unsafe for i in indices(x,1)
333+
s += x[i]
334+
end
335+
s
336+
end
337+
unsafe_fill!(a)
338+
for i = -3:3
339+
@test a[i] == i
340+
end
341+
@test unsafe_sum(a) == 0

0 commit comments

Comments
 (0)