From 28c0fa77e8d47edee8601d35cfda22812aaf182e Mon Sep 17 00:00:00 2001 From: Matt Bauman Date: Wed, 26 Apr 2017 19:43:35 -0500 Subject: [PATCH] Faster iteration over RepeatedRangeMatrix Given: ```jl R = RepeatedRangeMatrix(-500:500, 0:2000:10000000) f(X) = sum(x for x in X) ``` Before: ```jl julia> @btime f($R) 110.123 ms (3 allocations: 128 bytes) ``` After: ```jl julia> @btime f($R) 5.920 ms (4 allocations: 160 bytes) ``` --- src/repeatedrange.jl | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/repeatedrange.jl b/src/repeatedrange.jl index c83020b..943582c 100644 --- a/src/repeatedrange.jl +++ b/src/repeatedrange.jl @@ -14,6 +14,29 @@ RepeatedRangeMatrix{T}(r::Range{T}, at::AbstractVector{T}) = RepeatedRangeMatrix Base.size(R::RepeatedRangeMatrix) = (length(R.r), length(R.at)) @compat Base.IndexStyle(::Type{<:RepeatedRangeMatrix}) = IndexCartesian() +# This coupled iteration over the two fields is 10-20x faster than Cartesian iteration +@inline function Base.start(R::RepeatedRangeMatrix) + is = start(R.r) + idone = done(R.r, is) + js = start(R.at) + jdone = done(R.at, js) + return (idone | jdone) ? ((one(eltype(R.r)), is), (one(eltype(R.at)), js), true) : + (next(R.r, is), next(R.at, js), false) +end +@inline function Base.next(R::RepeatedRangeMatrix, state) + (i, is), (j, js), _ = state + val = i + j + if done(R.r, is) + if done(R.at, js) + return (val, ((i, is), (j, js), true)) + end + is = start(R.r) + j, js = next(R.at, js) + end + return (val, (next(R.r, is), (j, js), false)) +end +@inline Base.done(R::RepeatedRangeMatrix, state) = state[end] + # Scalar indexing @inline function Base.getindex(R::RepeatedRangeMatrix, i::Int, j::Int) @boundscheck checkbounds(R, i, j)