From 0314913de2d8c6aa9027ee880e3367926ea8fe4e Mon Sep 17 00:00:00 2001 From: timholy Date: Sat, 20 Sep 2014 17:17:41 -0500 Subject: [PATCH 1/7] Add a multidimensional (cartesian) iterator Closes #1917, closes #6437 --- base/dates/ranges.jl | 2 +- base/exports.jl | 2 + base/multidimensional.jl | 119 +++++++++++++++++++++++++++++++++++++++ base/range.jl | 4 +- base/sharedarray.jl | 8 +++ test/arrayops.jl | 51 +++++++++++++++++ 6 files changed, 183 insertions(+), 3 deletions(-) diff --git a/base/dates/ranges.jl b/base/dates/ranges.jl index 144c3552567bf..719c680705fa4 100644 --- a/base/dates/ranges.jl +++ b/base/dates/ranges.jl @@ -29,5 +29,5 @@ function in{T<:TimeType}(x::T, r::StepRange{T}) end Base.start{T<:TimeType}(r::StepRange{T}) = 0 -Base.next{T<:TimeType}(r::StepRange{T}, i) = (r.start+r.step*i,i+1) +Base.next{T<:TimeType}(r::StepRange{T}, i::Int) = (r.start+r.step*i,i+1) Base.done{T<:TimeType,S<:Period}(r::StepRange{T,S}, i::Integer) = length(r) <= i diff --git a/base/exports.jl b/base/exports.jl index 5b153f7b3ae9b..f42e76b075a4b 100644 --- a/base/exports.jl +++ b/base/exports.jl @@ -515,6 +515,8 @@ export cumsum, cumsum!, cumsum_kbn, + eachelement, + eachindex, extrema, fill!, fill, diff --git a/base/multidimensional.jl b/base/multidimensional.jl index 29c451c8ac5fe..034f7cb5c539b 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -1,3 +1,122 @@ +### Multidimensional iterators +module IteratorsMD + +import Base: start, done, next, getindex, setindex! +import Base: @nref, @ncall, @nif, @nexprs + +export eachelement, eachindex, linearindexing, LinearFast + +# Traits for linear indexing +abstract LinearIndexing +immutable LinearFast <: LinearIndexing end +immutable LinearSlow <: LinearIndexing end + +linearindexing(::AbstractArray) = LinearSlow() +linearindexing(::Array) = LinearFast() +linearindexing(::BitArray) = LinearFast() +linearindexing(::Range) = LinearFast() + +# this generates types like this: +# immutable Subscripts_3 <: Subscripts{3} +# I_1::Int +# I_2::Int +# I_3::Int +# end +# they are used as iterator states +# TODO: when tuples get improved, replace with a tuple-based implementation. See #6437. + +abstract Subscripts{N} # the state for all multidimensional iterators +abstract SizeIterator{N} # Iterator that visits the index associated with each element + +function gen_iterators(N::Int, with_shared=true) + # Create the types + namestate = symbol("Subscripts_$N") + namesize = symbol("SizeIterator_$N") + fieldnames = [symbol("I_$i") for i = 1:N] + fields = [Expr(:(::), fieldnames[i], :Int) for i = 1:N] + exstate = Expr(:type, false, Expr(:(<:), namestate, Expr(:curly, :Subscripts, N)), Expr(:block, fields...)) + dimsindexes = Expr[:(dims[$i]) for i = 1:N] + onesN = ones(Int, N) + infsN = fill(typemax(Int), N) + anyzero = Expr(:(||), [:(SZ.I.$(fieldnames[i]) == 0) for i = 1:N]...) + # Some necessary ambiguity resolution + exrange = N != 1 ? nothing : quote + next(R::StepRange, I::Subscripts_1) = R[I.I_1], Subscripts_1(I.I_1+1) + next{T}(R::UnitRange{T}, I::Subscripts_1) = R[I.I_1], Subscripts_1(I.I_1+1) + end + exshared = !with_shared ? nothing : quote + getindex{T}(S::SharedArray{T,$N}, state::$namestate) = S.s[state] + setindex!{T}(S::SharedArray{T,$N}, v, state::$namestate) = S.s[state] = v + end + quote + $exstate + immutable $namesize <: SizeIterator{$N} + I::$namestate + end + $namestate(dims::NTuple{$N,Int}) = $namestate($(dimsindexes...)) + _eachindex(dims::NTuple{$N,Int}) = $namesize($namestate(dims)) + + start{T}(AT::(AbstractArray{T,$N},LinearSlow)) = isempty(AT[1]) ? $namestate($(infsN...)) : $namestate($(onesN...)) + start(SZ::$namesize) = $anyzero ? $namestate($(infsN...)) : $namestate($(onesN...)) + + $exrange + + @inline function next{T}(A::AbstractArray{T,$N}, state::$namestate) + @inbounds v = A[state] + newstate = @nif $N d->(getfield(state,d) < size(A, d)) d->(@ncall($N, $namestate, k->(k>d ? getfield(state,k) : k==d ? getfield(state,k)+1 : 1))) + v, newstate + end + @inline function next(iter::$namesize, state::$namestate) + newstate = @nif $N d->(getfield(state,d) < getfield(iter.I,d)) d->(@ncall($N, $namestate, k->(k>d ? getfield(state,k) : k==d ? getfield(state,k)+1 : 1))) + state, newstate + end + + $exshared + getindex{T}(A::AbstractArray{T,$N}, state::$namestate) = @nref $N A d->getfield(state,d) + setindex!{T}(A::AbstractArray{T,$N}, v, state::$namestate) = (@nref $N A d->getfield(state,d)) = v + end +end + +# Ambiguity resolution +done(R::StepRange, I::Subscripts{1}) = getfield(I, 1) > length(R) +done(R::UnitRange, I::Subscripts{1}) = getfield(I, 1) > length(R) + +Base.start(A::AbstractArray) = start((A,linearindexing(A))) +start(::(AbstractArray,LinearFast)) = 1 +done{T,N}(A::AbstractArray{T,N}, I::Subscripts{N}) = getfield(I, N) > size(A, N) +done{N}(iter::SizeIterator{N}, I::Subscripts{N}) = getfield(I, N) > getfield(iter.I, N) + +eachindex(A::AbstractArray) = eachindex(size(A)) + +let implemented = IntSet() +global eachindex +global eachelement +function eachindex{N}(t::NTuple{N,Int}) + if !in(N, implemented) + eval(gen_iterators(N)) + end + _eachindex(t) +end +function eachelement{T,N}(A::AbstractArray{T,N}) + if !in(N, implemented) + eval(gen_iterators(N)) + end + A +end +end + +# Pre-generate for low dimensions +for N = 1:8 + eval(gen_iterators(N, false)) + eval(:(eachindex(t::NTuple{$N,Int}) = _eachindex(t))) + eval(:(eachelement{T}(A::AbstractArray{T,$N}) = A)) +end + +end # IteratorsMD + +using .IteratorsMD + + ### From array.jl @ngenerate N Void function checksize(A::AbstractArray, I::NTuple{N, Any}...) diff --git a/base/range.jl b/base/range.jl index 1cf7f5f4d431a..7c21201509bff 100644 --- a/base/range.jl +++ b/base/range.jl @@ -235,8 +235,8 @@ copy(r::Range) = r ## iteration start(r::FloatRange) = 0 -next{T}(r::FloatRange{T}, i) = (convert(T, (r.start + i*r.step)/r.divisor), i+1) -done(r::FloatRange, i) = (length(r) <= i) +next{T}(r::FloatRange{T}, i::Int) = (convert(T, (r.start + i*r.step)/r.divisor), i+1) +done(r::FloatRange, i::Int) = (length(r) <= i) # NOTE: For ordinal ranges, we assume start+step might be from a # lifted domain (e.g. Int8+Int8 => Int); use that for iterating. diff --git a/base/sharedarray.jl b/base/sharedarray.jl index 2c22a36cc9ead..22147d11d4294 100644 --- a/base/sharedarray.jl +++ b/base/sharedarray.jl @@ -207,6 +207,14 @@ end convert(::Type{Array}, S::SharedArray) = S.s # # pass through getindex and setindex! - they always work on the complete array unlike DArrays +for N = 1:8 + name = symbol("Subscripts_$N") + @eval begin + getindex{T}(S::SharedArray{T,$N}, I::IteratorsMD.$name) = getindex(S.s, I) + setindex!{T}(S::SharedArray{T,$N}, v, I::IteratorsMD.$name) = setindex!(S.s, v, I) + end +end + getindex(S::SharedArray) = getindex(S.s) getindex(S::SharedArray, I::Real) = getindex(S.s, I) getindex(S::SharedArray, I::AbstractArray) = getindex(S.s, I) diff --git a/test/arrayops.jl b/test/arrayops.jl index 143f7688655e0..5a700fb6a8153 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -925,3 +925,54 @@ end b718cbc = 5 @test b718cbc[1.0] == 5 @test_throws InexactError b718cbc[1.1] + +# Multidimensional iterators +function mdsum(A) + s = 0.0 + for a in eachelement(A) + s += a + end + s +end + +function mdsum2(A) + s = 0.0 + @inbounds for I in eachindex(A) + s += A[I] + end + s +end + +a = [1:5] +@test isa(Base.linearindexing(a), Base.LinearFast) +b = sub(a, :) +@test isa(Base.linearindexing(b), Base.IteratorsMD.LinearSlow) +shp = [5] +for i = 1:10 + A = reshape(a, tuple(shp...)) + @test mdsum(A) == 15 + @test mdsum2(A) == 15 + B = sub(A, ntuple(i, i->Colon())...) + @test mdsum(B) == 15 + @test mdsum2(B) == 15 + unshift!(shp, 1) +end + +a = [1:10] +shp = [2,5] +for i = 2:10 + A = reshape(a, tuple(shp...)) + @test mdsum(A) == 55 + @test mdsum2(A) == 55 + B = sub(A, ntuple(i, i->Colon())...) + @test mdsum(B) == 55 + @test mdsum2(B) == 55 + insert!(shp, 2, 1) +end + +a = ones(0,5) +b = sub(a, :, :) +@test mdsum(b) == 0 +a = ones(5,0) +b = sub(a, :, :) +@test mdsum(b) == 0 From db2fa01caa7c08148b40cd42acc70bd1c640e96f Mon Sep 17 00:00:00 2001 From: timholy Date: Sat, 20 Sep 2014 17:18:16 -0500 Subject: [PATCH 2/7] Make the output of setindex! for SharedArrays consistent with other implementations --- base/sharedarray.jl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/base/sharedarray.jl b/base/sharedarray.jl index 22147d11d4294..1ab238248c037 100644 --- a/base/sharedarray.jl +++ b/base/sharedarray.jl @@ -220,10 +220,10 @@ getindex(S::SharedArray, I::Real) = getindex(S.s, I) getindex(S::SharedArray, I::AbstractArray) = getindex(S.s, I) @nsplat N 1:5 getindex(S::SharedArray, I::NTuple{N,Any}...) = getindex(S.s, I...) -setindex!(S::SharedArray, x) = (setindex!(S.s, x); S) -setindex!(S::SharedArray, x, I::Real) = (setindex!(S.s, x, I); S) -setindex!(S::SharedArray, x, I::AbstractArray) = (setindex!(S.s, x, I); S) -@nsplat N 1:5 setindex!(S::SharedArray, x, I::NTuple{N,Any}...) = (setindex!(S.s, x, I...); S) +setindex!(S::SharedArray, x) = setindex!(S.s, x) +setindex!(S::SharedArray, x, I::Real) = setindex!(S.s, x, I) +setindex!(S::SharedArray, x, I::AbstractArray) = setindex!(S.s, x, I) +@nsplat N 1:5 setindex!(S::SharedArray, x, I::NTuple{N,Any}...) = setindex!(S.s, x, I...) function fill!(S::SharedArray, v) f = S->fill!(S.loc_subarr_1d, v) From dbd1bd4d8613ab6c297b12a1c3d6220d9f3ff877 Mon Sep 17 00:00:00 2001 From: timholy Date: Tue, 11 Nov 2014 08:41:24 -0600 Subject: [PATCH 3/7] Make type-construction more modular See https://github.com/JuliaLang/julia/pull/8432#issuecomment-62536295 --- base/multidimensional.jl | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/base/multidimensional.jl b/base/multidimensional.jl index 034f7cb5c539b..fb7c44c47abac 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -28,7 +28,7 @@ linearindexing(::Range) = LinearFast() abstract Subscripts{N} # the state for all multidimensional iterators abstract SizeIterator{N} # Iterator that visits the index associated with each element -function gen_iterators(N::Int, with_shared=true) +function gen_iterators(N::Int, with_shared=Base.is_unix(OS_NAME)) # Create the types namestate = symbol("Subscripts_$N") namesize = symbol("SizeIterator_$N") @@ -81,7 +81,7 @@ end done(R::StepRange, I::Subscripts{1}) = getfield(I, 1) > length(R) done(R::UnitRange, I::Subscripts{1}) = getfield(I, 1) > length(R) -Base.start(A::AbstractArray) = start((A,linearindexing(A))) +start(A::AbstractArray) = start((A,linearindexing(A))) start(::(AbstractArray,LinearFast)) = 1 done{T,N}(A::AbstractArray{T,N}, I::Subscripts{N}) = getfield(I, N) > size(A, N) done{N}(iter::SizeIterator{N}, I::Subscripts{N}) = getfield(I, N) > getfield(iter.I, N) @@ -89,25 +89,27 @@ done{N}(iter::SizeIterator{N}, I::Subscripts{N}) = getfield(I, N) > getfield(ite eachindex(A::AbstractArray) = eachindex(size(A)) let implemented = IntSet() -global eachindex -global eachelement -function eachindex{N}(t::NTuple{N,Int}) +global mditer_register +function mditer_register(N::Int) if !in(N, implemented) eval(gen_iterators(N)) end +end +end + +function eachindex{N}(t::NTuple{N,Int}) + mditer_register(N) _eachindex(t) end + function eachelement{T,N}(A::AbstractArray{T,N}) - if !in(N, implemented) - eval(gen_iterators(N)) - end + mditer_register(N) A end -end # Pre-generate for low dimensions for N = 1:8 - eval(gen_iterators(N, false)) + eval(gen_iterators(N, false)) # SharedArray is not yet defined eval(:(eachindex(t::NTuple{$N,Int}) = _eachindex(t))) eval(:(eachelement{T}(A::AbstractArray{T,$N}) = A)) end From b9744b1840f5221e73dfb63445f22693b4354755 Mon Sep 17 00:00:00 2001 From: Jutho Haegeman Date: Wed, 12 Nov 2014 15:54:27 -0600 Subject: [PATCH 4/7] Rework iteration using stagedfunctions --- base/multidimensional.jl | 161 +++++++++++++++++++-------------------- base/sharedarray.jl | 12 +-- test/arrayops.jl | 2 +- 3 files changed, 79 insertions(+), 96 deletions(-) diff --git a/base/multidimensional.jl b/base/multidimensional.jl index fb7c44c47abac..e461ca04f2f7f 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -4,7 +4,7 @@ module IteratorsMD import Base: start, done, next, getindex, setindex! import Base: @nref, @ncall, @nif, @nexprs -export eachelement, eachindex, linearindexing, LinearFast +export eachindex, linearindexing, LinearFast # Traits for linear indexing abstract LinearIndexing @@ -16,103 +16,96 @@ linearindexing(::Array) = LinearFast() linearindexing(::BitArray) = LinearFast() linearindexing(::Range) = LinearFast() -# this generates types like this: -# immutable Subscripts_3 <: Subscripts{3} -# I_1::Int -# I_2::Int -# I_3::Int -# end -# they are used as iterator states -# TODO: when tuples get improved, replace with a tuple-based implementation. See #6437. +abstract CartesianIndex{N} # the state for all multidimensional iterators +abstract IndexIterator{N} # Iterator that visits the index associated with each element -abstract Subscripts{N} # the state for all multidimensional iterators -abstract SizeIterator{N} # Iterator that visits the index associated with each element +stagedfunction Base.call{N}(::Type{CartesianIndex},index::NTuple{N,Int}) + indextype,itertype=gen_cartesian(N) + return :($indextype(index)) +end +stagedfunction Base.call{N}(::Type{IndexIterator},index::NTuple{N,Int}) + indextype,itertype=gen_cartesian(N) + return :($itertype(index)) +end -function gen_iterators(N::Int, with_shared=Base.is_unix(OS_NAME)) +let implemented = IntSet() +global gen_cartesian +function gen_cartesian(N::Int, with_shared=Base.is_unix(OS_NAME)) # Create the types - namestate = symbol("Subscripts_$N") - namesize = symbol("SizeIterator_$N") - fieldnames = [symbol("I_$i") for i = 1:N] - fields = [Expr(:(::), fieldnames[i], :Int) for i = 1:N] - exstate = Expr(:type, false, Expr(:(<:), namestate, Expr(:curly, :Subscripts, N)), Expr(:block, fields...)) - dimsindexes = Expr[:(dims[$i]) for i = 1:N] - onesN = ones(Int, N) - infsN = fill(typemax(Int), N) - anyzero = Expr(:(||), [:(SZ.I.$(fieldnames[i]) == 0) for i = 1:N]...) - # Some necessary ambiguity resolution - exrange = N != 1 ? nothing : quote - next(R::StepRange, I::Subscripts_1) = R[I.I_1], Subscripts_1(I.I_1+1) - next{T}(R::UnitRange{T}, I::Subscripts_1) = R[I.I_1], Subscripts_1(I.I_1+1) - end - exshared = !with_shared ? nothing : quote - getindex{T}(S::SharedArray{T,$N}, state::$namestate) = S.s[state] - setindex!{T}(S::SharedArray{T,$N}, v, state::$namestate) = S.s[state] = v - end - quote - $exstate - immutable $namesize <: SizeIterator{$N} - I::$namestate - end - $namestate(dims::NTuple{$N,Int}) = $namestate($(dimsindexes...)) - _eachindex(dims::NTuple{$N,Int}) = $namesize($namestate(dims)) - - start{T}(AT::(AbstractArray{T,$N},LinearSlow)) = isempty(AT[1]) ? $namestate($(infsN...)) : $namestate($(onesN...)) - start(SZ::$namesize) = $anyzero ? $namestate($(infsN...)) : $namestate($(onesN...)) - - $exrange - - @inline function next{T}(A::AbstractArray{T,$N}, state::$namestate) - @inbounds v = A[state] - newstate = @nif $N d->(getfield(state,d) < size(A, d)) d->(@ncall($N, $namestate, k->(k>d ? getfield(state,k) : k==d ? getfield(state,k)+1 : 1))) - v, newstate + indextype = symbol("CartesianIndex_$N") + itertype = symbol("IndexIterator_$N") + if !in(N,implemented) + fieldnames = [symbol("I_$i") for i = 1:N] + fields = [Expr(:(::), fieldnames[i], :Int) for i = 1:N] + extype = Expr(:type, false, Expr(:(<:), indextype, Expr(:curly, :CartesianIndex, N)), Expr(:block, fields...)) + exindices = Expr[:(index[$i]) for i = 1:N] + + onesN = ones(Int, N) + infsN = fill(typemax(Int), N) + anyzero = Expr(:(||), [:(iter.dims.$(fieldnames[i]) == 0) for i = 1:N]...) + + # Some necessary ambiguity resolution + exrange = N != 1 ? nothing : quote + next(R::StepRange, I::CartesianIndex_1) = R[I.I_1], CartesianIndex_1(I.I_1+1) + next{T}(R::UnitRange{T}, I::CartesianIndex_1) = R[I.I_1], CartesianIndex_1(I.I_1+1) end - @inline function next(iter::$namesize, state::$namestate) - newstate = @nif $N d->(getfield(state,d) < getfield(iter.I,d)) d->(@ncall($N, $namestate, k->(k>d ? getfield(state,k) : k==d ? getfield(state,k)+1 : 1))) - state, newstate + exshared = !with_shared ? nothing : quote + getindex{T}(S::SharedArray{T,$N}, I::$indextype) = S.s[I] + setindex!{T}(S::SharedArray{T,$N}, v, I::$indextype) = S.s[I] = v end + totalex = quote + # type definition + $extype + # extra constructor from tuple + $indextype(index::NTuple{$N,Int}) = $indextype($(exindices...)) + + immutable $itertype <: IndexIterator{$N} + dims::$indextype + end + $itertype(dims::NTuple{$N,Int})=$itertype($indextype(dims)) + + # getindex and setindex! + $exshared + getindex{T}(A::AbstractArray{T,$N}, index::$indextype) = @nref $N A d->getfield(index,d) + setindex!{T}(A::AbstractArray{T,$N}, v, index::$indextype) = (@nref $N A d->getfield(index,d)) = v + + # next iteration + $exrange + @inline function next{T}(A::AbstractArray{T,$N}, state::$indextype) + @inbounds v = A[state] + newstate = @nif $N d->(getfield(state,d) < size(A, d)) d->(@ncall($N, $indextype, k->(k>d ? getfield(state,k) : k==d ? getfield(state,k)+1 : 1))) + v, newstate + end + @inline function next(iter::$itertype, state::$indextype) + newstate = @nif $N d->(getfield(state,d) < getfield(iter.dims,d)) d->(@ncall($N, $indextype, k->(k>d ? getfield(state,k) : k==d ? getfield(state,k)+1 : 1))) + state, newstate + end - $exshared - getindex{T}(A::AbstractArray{T,$N}, state::$namestate) = @nref $N A d->getfield(state,d) - setindex!{T}(A::AbstractArray{T,$N}, v, state::$namestate) = (@nref $N A d->getfield(state,d)) = v + # start + start(iter::$itertype) = $anyzero ? $indextype($(infsN...)) : $indextype($(onesN...)) + end + eval(totalex) + push!(implemented,N) end + return indextype, itertype +end end -# Ambiguity resolution -done(R::StepRange, I::Subscripts{1}) = getfield(I, 1) > length(R) -done(R::UnitRange, I::Subscripts{1}) = getfield(I, 1) > length(R) +# Iteration +eachindex(A::AbstractArray) = IndexIterator(size(A)) +# start iteration start(A::AbstractArray) = start((A,linearindexing(A))) start(::(AbstractArray,LinearFast)) = 1 -done{T,N}(A::AbstractArray{T,N}, I::Subscripts{N}) = getfield(I, N) > size(A, N) -done{N}(iter::SizeIterator{N}, I::Subscripts{N}) = getfield(I, N) > getfield(iter.I, N) - -eachindex(A::AbstractArray) = eachindex(size(A)) - -let implemented = IntSet() -global mditer_register -function mditer_register(N::Int) - if !in(N, implemented) - eval(gen_iterators(N)) - end -end -end - -function eachindex{N}(t::NTuple{N,Int}) - mditer_register(N) - _eachindex(t) -end +start{T,N}(AT::(AbstractArray{T,N},LinearSlow)) = CartesianIndex(ntuple(N,n->(isempty(AT[1]) ? typemax(Int) : 1))) -function eachelement{T,N}(A::AbstractArray{T,N}) - mditer_register(N) - A -end +# Ambiguity resolution +done(R::StepRange, I::CartesianIndex{1}) = getfield(I, 1) > length(R) +done(R::UnitRange, I::CartesianIndex{1}) = getfield(I, 1) > length(R) +done(R::FloatRange, I::CartesianIndex{1}) = getfield(I, 1) > length(R) -# Pre-generate for low dimensions -for N = 1:8 - eval(gen_iterators(N, false)) # SharedArray is not yet defined - eval(:(eachindex(t::NTuple{$N,Int}) = _eachindex(t))) - eval(:(eachelement{T}(A::AbstractArray{T,$N}) = A)) -end +done{T,N}(A::AbstractArray{T,N}, I::CartesianIndex{N}) = getfield(I, N) > size(A, N) +done{N}(iter::IndexIterator{N}, I::CartesianIndex{N}) = getfield(I, N) > getfield(iter.dims, N) end # IteratorsMD diff --git a/base/sharedarray.jl b/base/sharedarray.jl index 1ab238248c037..51a78f1e15a96 100644 --- a/base/sharedarray.jl +++ b/base/sharedarray.jl @@ -206,15 +206,7 @@ end convert(::Type{Array}, S::SharedArray) = S.s -# # pass through getindex and setindex! - they always work on the complete array unlike DArrays -for N = 1:8 - name = symbol("Subscripts_$N") - @eval begin - getindex{T}(S::SharedArray{T,$N}, I::IteratorsMD.$name) = getindex(S.s, I) - setindex!{T}(S::SharedArray{T,$N}, v, I::IteratorsMD.$name) = setindex!(S.s, v, I) - end -end - +# pass through getindex and setindex! - they always work on the complete array unlike DArrays getindex(S::SharedArray) = getindex(S.s) getindex(S::SharedArray, I::Real) = getindex(S.s, I) getindex(S::SharedArray, I::AbstractArray) = getindex(S.s, I) @@ -385,5 +377,3 @@ end end @unix_only shm_open(shm_seg_name, oflags, permissions) = ccall(:shm_open, Int, (Ptr{UInt8}, Int, Int), shm_seg_name, oflags, permissions) - - diff --git a/test/arrayops.jl b/test/arrayops.jl index 5a700fb6a8153..00f6b5e673809 100644 --- a/test/arrayops.jl +++ b/test/arrayops.jl @@ -929,7 +929,7 @@ b718cbc = 5 # Multidimensional iterators function mdsum(A) s = 0.0 - for a in eachelement(A) + for a in A s += a end s From 05a5277a7130eccc9f35497956c1870a0be513c2 Mon Sep 17 00:00:00 2001 From: Jutho Haegeman Date: Fri, 14 Nov 2014 00:57:50 +0100 Subject: [PATCH 5/7] fix type inference for iteration with stagedfunction --- base/multidimensional.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/multidimensional.jl b/base/multidimensional.jl index e461ca04f2f7f..2568a5801321a 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -97,7 +97,7 @@ eachindex(A::AbstractArray) = IndexIterator(size(A)) # start iteration start(A::AbstractArray) = start((A,linearindexing(A))) start(::(AbstractArray,LinearFast)) = 1 -start{T,N}(AT::(AbstractArray{T,N},LinearSlow)) = CartesianIndex(ntuple(N,n->(isempty(AT[1]) ? typemax(Int) : 1))) +start{T,N}(AT::(AbstractArray{T,N},LinearSlow)) = CartesianIndex(ntuple(N,n->ifelse(isempty(AT[1]),typemax(Int),1))::NTuple{N,Int}) # Ambiguity resolution done(R::StepRange, I::CartesianIndex{1}) = getfield(I, 1) > length(R) From e042cbe186b88164efc2b677335e63ffc339d537 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Thu, 13 Nov 2014 22:26:51 -0600 Subject: [PATCH 6/7] Move AbstractArray traits earlier to avoid overwriting `start` This prevents a build warning --- base/abstractarray.jl | 13 ++++++++++++- base/multidimensional.jl | 18 +++++------------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index 98574dd2cb22c..eb8fb743921de 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -58,6 +58,16 @@ function trailingsize(A, n) return s end +## Traits for array types ## + +abstract LinearIndexing +immutable LinearFast <: LinearIndexing end +immutable LinearSlow <: LinearIndexing end + +linearindexing(::AbstractArray) = LinearSlow() +linearindexing(::Array) = LinearFast() +linearindexing(::Range) = LinearFast() + ## Bounds checking ## checkbounds(sz::Int, i::Int) = 1 <= i <= sz || throw(BoundsError()) checkbounds(sz::Int, i::Real) = checkbounds(sz, to_index(i)) @@ -241,7 +251,8 @@ zero{T}(x::AbstractArray{T}) = fill!(similar(x), zero(T)) ## iteration support for arrays as ranges ## -start(a::AbstractArray) = 1 +start(A::AbstractArray) = start((A,linearindexing(A))) +start(::(AbstractArray,LinearFast)) = 1 next(a::AbstractArray,i) = (a[i],i+1) done(a::AbstractArray,i) = (i > length(a)) isempty(a::AbstractArray) = (length(a) == 0) diff --git a/base/multidimensional.jl b/base/multidimensional.jl index 2568a5801321a..74fda3f355532 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -1,23 +1,17 @@ ### Multidimensional iterators module IteratorsMD -import Base: start, done, next, getindex, setindex! -import Base: @nref, @ncall, @nif, @nexprs +import Base: start, done, next, getindex, setindex!, linearindexing +import Base: @nref, @ncall, @nif, @nexprs, LinearFast, LinearSlow -export eachindex, linearindexing, LinearFast +export eachindex # Traits for linear indexing -abstract LinearIndexing -immutable LinearFast <: LinearIndexing end -immutable LinearSlow <: LinearIndexing end - -linearindexing(::AbstractArray) = LinearSlow() -linearindexing(::Array) = LinearFast() linearindexing(::BitArray) = LinearFast() -linearindexing(::Range) = LinearFast() +# Iterator/state abstract CartesianIndex{N} # the state for all multidimensional iterators -abstract IndexIterator{N} # Iterator that visits the index associated with each element +abstract IndexIterator{N} # Iterator that visits the index associated with each element stagedfunction Base.call{N}(::Type{CartesianIndex},index::NTuple{N,Int}) indextype,itertype=gen_cartesian(N) @@ -95,8 +89,6 @@ end eachindex(A::AbstractArray) = IndexIterator(size(A)) # start iteration -start(A::AbstractArray) = start((A,linearindexing(A))) -start(::(AbstractArray,LinearFast)) = 1 start{T,N}(AT::(AbstractArray{T,N},LinearSlow)) = CartesianIndex(ntuple(N,n->ifelse(isempty(AT[1]),typemax(Int),1))::NTuple{N,Int}) # Ambiguity resolution From 2fa852d8588214b7807fa393ccb3d55864b3e1a2 Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Sat, 15 Nov 2014 00:50:55 -0600 Subject: [PATCH 7/7] Avoid confusion with start(::Tuple) iteration --- base/abstractarray.jl | 4 ++-- base/multidimensional.jl | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/base/abstractarray.jl b/base/abstractarray.jl index eb8fb743921de..30541de33c1c2 100644 --- a/base/abstractarray.jl +++ b/base/abstractarray.jl @@ -251,8 +251,8 @@ zero{T}(x::AbstractArray{T}) = fill!(similar(x), zero(T)) ## iteration support for arrays as ranges ## -start(A::AbstractArray) = start((A,linearindexing(A))) -start(::(AbstractArray,LinearFast)) = 1 +start(A::AbstractArray) = _start(A,linearindexing(A)) +_start(::AbstractArray,::LinearFast) = 1 next(a::AbstractArray,i) = (a[i],i+1) done(a::AbstractArray,i) = (i > length(a)) isempty(a::AbstractArray) = (length(a) == 0) diff --git a/base/multidimensional.jl b/base/multidimensional.jl index 74fda3f355532..9597fe523ea36 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -1,7 +1,7 @@ ### Multidimensional iterators module IteratorsMD -import Base: start, done, next, getindex, setindex!, linearindexing +import Base: start, _start, done, next, getindex, setindex!, linearindexing import Base: @nref, @ncall, @nif, @nexprs, LinearFast, LinearSlow export eachindex @@ -89,7 +89,7 @@ end eachindex(A::AbstractArray) = IndexIterator(size(A)) # start iteration -start{T,N}(AT::(AbstractArray{T,N},LinearSlow)) = CartesianIndex(ntuple(N,n->ifelse(isempty(AT[1]),typemax(Int),1))::NTuple{N,Int}) +_start{T,N}(A::AbstractArray{T,N},::LinearSlow) = CartesianIndex(ntuple(N,n->ifelse(isempty(A),typemax(Int),1))::NTuple{N,Int}) # Ambiguity resolution done(R::StepRange, I::CartesianIndex{1}) = getfield(I, 1) > length(R)