|  | 
| 1 | 1 | ### Multidimensional iterators | 
| 2 | 2 | module IteratorsMD | 
| 3 | 3 | 
 | 
| 4 |  | -import Base: eltype, length, start, _start, done, next, last, getindex, setindex!, linearindexing, min, max | 
|  | 4 | +import Base: eltype, length, start, done, next, last, getindex, setindex!, linearindexing, min, max, eachindex | 
| 5 | 5 | import Base: simd_outer_range, simd_inner_length, simd_index | 
| 6 | 6 | import Base: @nref, @ncall, @nif, @nexprs, LinearFast, LinearSlow, to_index | 
| 7 | 7 | 
 | 
| 8 |  | -export CartesianIndex, CartesianRange, eachindex | 
|  | 8 | +export CartesianIndex, CartesianRange | 
| 9 | 9 | 
 | 
| 10 | 10 | # Traits for linear indexing | 
| 11 | 11 | linearindexing(::BitArray) = LinearFast() | 
| @@ -110,60 +110,37 @@ stagedfunction CartesianRange{N}(I::CartesianIndex{N}) | 
| 110 | 110 | end | 
| 111 | 111 | CartesianRange{N}(sz::NTuple{N,Int}) = CartesianRange(CartesianIndex(sz)) | 
| 112 | 112 | 
 | 
| 113 |  | -stagedfunction eachindex{T,N}(A::AbstractArray{T,N}) | 
|  | 113 | +stagedfunction eachindex{T,N}(::LinearSlow, A::AbstractArray{T,N}) | 
| 114 | 114 |     startargs = fill(1, N) | 
| 115 | 115 |     stopargs = [:(size(A,$i)) for i=1:N] | 
| 116 |  | -    :(CartesianRange(CartesianIndex{$N}($(startargs...)), CartesianIndex{$N}($(stopargs...)))) | 
|  | 116 | +    meta = Expr(:meta, :inline) | 
|  | 117 | +    :($meta; CartesianRange(CartesianIndex{$N}($(startargs...)), CartesianIndex{$N}($(stopargs...)))) | 
| 117 | 118 | end | 
| 118 | 119 | 
 | 
| 119 | 120 | eltype{I}(::Type{CartesianRange{I}}) = I | 
| 120 | 121 | eltype{I}(::CartesianRange{I}) = I | 
| 121 | 122 | 
 | 
| 122 |  | -stagedfunction start{I}(iter::CartesianRange{I}) | 
| 123 |  | -    N=length(I) | 
| 124 |  | -    finishedex = Expr(:(||), [:(iter.stop[$i] < iter.start[$i]) for i = 1:N]...) | 
| 125 |  | -    :(return $finishedex, iter.start) | 
| 126 |  | -end | 
| 127 |  | - | 
| 128 |  | -stagedfunction _start{T,N}(A::AbstractArray{T,N}, ::LinearSlow) | 
| 129 |  | -    args = fill(1, N) | 
| 130 |  | -    :(return isempty(A), CartesianIndex{$N}($(args...))) | 
| 131 |  | -end | 
| 132 |  | - | 
| 133 |  | -# Prevent an ambiguity warning | 
| 134 |  | -next(R::StepRange, state::(Bool, CartesianIndex{1})) = (index=state[2]; return R[index], (index[1]==length(R), CartesianIndex{1}(index[1]+1))) | 
| 135 |  | -next{T}(R::UnitRange{T}, state::(Bool, CartesianIndex{1})) = (index=state[2]; return R[index], (index[1]==length(R), CartesianIndex{1}(index[1]+1))) | 
| 136 |  | -done(R::StepRange, state::(Bool, CartesianIndex{1})) = state[1] | 
| 137 |  | -done(R::UnitRange, state::(Bool, CartesianIndex{1})) = state[1] | 
| 138 |  | - | 
| 139 |  | -stagedfunction next{T,N}(A::AbstractArray{T,N}, state::(Bool, CartesianIndex{N})) | 
| 140 |  | -    I = state[2] | 
| 141 |  | -    finishedex = (N==0 ? true : :(newindex[$N] > size(A, $N))) | 
|  | 123 | +start(iter::CartesianRange) = iter.start | 
|  | 124 | +stagedfunction next{I<:CartesianIndex}(iter::CartesianRange{I}, state) | 
|  | 125 | +    N = length(I) | 
| 142 | 126 |     meta = Expr(:meta, :inline) | 
| 143 | 127 |     quote | 
| 144 | 128 |         $meta | 
| 145 |  | -        index=state[2] | 
| 146 |  | -        @inbounds v = A[index] | 
| 147 |  | -        newindex=@nif $N d->(index[d] < size(A, d)) d->@ncall($N, $I, k->(k>d ? index[k] : k==d ? index[k]+1 : 1)) | 
| 148 |  | -        finished=$finishedex | 
| 149 |  | -        v, (finished,newindex) | 
|  | 129 | +        index=state | 
|  | 130 | +        @nif $N d->(index[d] < iter.stop[d]) d->(@nexprs($N, k->(ind_k = ifelse(k>=d, index[k] + (k==d), iter.start[k])))) | 
|  | 131 | +        newindex = @ncall $N $I ind | 
|  | 132 | +        index, newindex | 
| 150 | 133 |     end | 
| 151 | 134 | end | 
| 152 |  | -stagedfunction next{I<:CartesianIndex}(iter::CartesianRange{I}, state::(Bool, I)) | 
|  | 135 | +stagedfunction done{I<:CartesianIndex}(iter::CartesianRange{I}, state) | 
| 153 | 136 |     N = length(I) | 
| 154 |  | -    finishedex = (N==0 ? true : :(newindex[$N] > iter.stop[$N])) | 
| 155 |  | -    meta = Expr(:meta, :inline) | 
| 156 |  | -    quote | 
| 157 |  | -        $meta | 
| 158 |  | -        index=state[2] | 
| 159 |  | -        newindex=@nif $N d->(index[d] < iter.stop[d]) d->@ncall($N, $I, k->(k>d ? index[k] : k==d ? index[k]+1 : iter.start[k])) | 
| 160 |  | -        finished=$finishedex | 
| 161 |  | -        index, (finished,newindex) | 
| 162 |  | -    end | 
|  | 137 | +    :(state[$N] > iter.stop[$N]) | 
| 163 | 138 | end | 
| 164 | 139 | 
 | 
| 165 |  | -done{T,N}(A::AbstractArray{T,N}, state::(Bool, CartesianIndex{N})) = state[1] | 
| 166 |  | -done{I<:CartesianIndex}(iter::CartesianRange{I}, state::(Bool, I)) = state[1] | 
|  | 140 | +# 0-d cartesian ranges are special-cased to iterate once and only once | 
|  | 141 | +start{I<:CartesianIndex{0}}(iter::CartesianRange{I}) = false | 
|  | 142 | +next{I<:CartesianIndex{0}}(iter::CartesianRange{I}, state) = iter.start, true | 
|  | 143 | +done{I<:CartesianIndex{0}}(iter::CartesianRange{I}, state) = state | 
| 167 | 144 | 
 | 
| 168 | 145 | stagedfunction length{I<:CartesianIndex}(iter::CartesianRange{I}) | 
| 169 | 146 |     N = length(I) | 
| @@ -502,7 +479,7 @@ function copy!{T,N}(dest::AbstractArray{T,N}, src::AbstractArray{T,N}) | 
| 502 | 479 |             break | 
| 503 | 480 |         end | 
| 504 | 481 |     end | 
| 505 |  | -    if samesize | 
|  | 482 | +    if samesize && linearindexing(dest) == linearindexing(src) | 
| 506 | 483 |         for I in eachindex(dest) | 
| 507 | 484 |             @inbounds dest[I] = src[I] | 
| 508 | 485 |         end | 
|  | 
0 commit comments