From ef49fcb22025a50de51f46aaea6667eee2a2452c Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Wed, 8 Mar 2017 11:38:33 -0600 Subject: [PATCH 1/4] Improve docs for copy! --- base/docs/helpdb/Base.jl | 7 ------- base/multidimensional.jl | 25 +++++++++++++++++++++++++ doc/src/stdlib/arrays.md | 1 + 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/base/docs/helpdb/Base.jl b/base/docs/helpdb/Base.jl index d725d54390b6d..d5f9000b947be 100644 --- a/base/docs/helpdb/Base.jl +++ b/base/docs/helpdb/Base.jl @@ -2027,13 +2027,6 @@ algorithms. See [`muladd`](@ref). """ fma -""" - copy!(dest, src) - -Copy all elements from collection `src` to array `dest`. Returns `dest`. -""" -copy!(dest,src) - """ copy!(dest, do, src, so, N) diff --git a/base/multidimensional.jl b/base/multidimensional.jl index 6e0b8a567b57f..f6a6814351f86 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -209,6 +209,16 @@ module IteratorsMD @inline _split{N}(tN::NTuple{N,Any}, ::Tuple{}, ::Type{Val{N}}) = tN, () # ambig. @inline _split{N}(tN, ::Tuple{}, ::Type{Val{N}}) = tN, () @inline _split{N}(tN::NTuple{N,Any}, trest, ::Type{Val{N}}) = tN, trest + + @inline function split(I::CartesianIndex, V::Type{<:Val}) + i, j = split(I.I, V) + CartesianIndex(i), CartesianIndex(j) + end + function split(R::CartesianRange, V::Type{<:Val}) + istart, jstart = split(first(R), V) + istop, jstop = split(last(R), V) + CartesianRange(istart, istop), CartesianRange(jstart, jstop) + end end # IteratorsMD @@ -781,6 +791,13 @@ function fill!{T}(A::AbstractArray{T}, x) A end +""" + copy!(dest, src) -> dest + +Copy all elements from collection `src` to array `dest`. +""" +copy!(dest, src) + function copy!{T,N}(dest::AbstractArray{T,N}, src::AbstractArray{T,N}) @boundscheck checkbounds(dest, indices(src)...) for I in eachindex(IndexStyle(src,dest), src) @@ -805,6 +822,14 @@ function copy!(dest::AbstractArray, Rdest::CartesianRange, src::AbstractArray, R dest end +""" + copy!(dest, Rdest::CartesianRange, src, Rsrc::CartesianRange) -> dest + +Copy the block of `src` in the range of `Rsrc` to the block of `dest` +in the range of `Rdest`. The sizes of the two regions must match. +""" +copy!(::AbstractArray, ::CartesianRange, ::AbstractArray, ::CartesianRange) + # circshift! circshift!(dest::AbstractArray, src, ::Tuple{}) = copy!(dest, src) """ diff --git a/doc/src/stdlib/arrays.md b/doc/src/stdlib/arrays.md index 0e097e7bb71a7..87c06ac591ebb 100644 --- a/doc/src/stdlib/arrays.md +++ b/doc/src/stdlib/arrays.md @@ -61,6 +61,7 @@ Base.Broadcast.broadcast_setindex! ```@docs Base.getindex(::AbstractArray, ::Any...) Base.setindex!(::AbstractArray, ::Any, ::Any...) +Base.copy!(::AbstractArray, ::CartesianRange, ::AbstractArray, ::CartesianRange) Base.isassigned Base.Colon Base.CartesianIndex From 810cade782d58217ac1c422d52e7bd7c952c0738 Mon Sep 17 00:00:00 2001 From: JKrehl Date: Wed, 8 Mar 2017 11:43:47 -0600 Subject: [PATCH 2/4] Speed up copy!(dest, Rdest, src, Rsrc) for CartesianRange inputs --- base/multidimensional.jl | 33 ++++++++++++++++++++------------- test/copy.jl | 15 ++++++++++++++- 2 files changed, 34 insertions(+), 14 deletions(-) diff --git a/base/multidimensional.jl b/base/multidimensional.jl index f6a6814351f86..8c5ce2ad155fd 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -806,20 +806,27 @@ function copy!{T,N}(dest::AbstractArray{T,N}, src::AbstractArray{T,N}) dest end -function copy!(dest::AbstractArray, Rdest::CartesianRange, src::AbstractArray, Rsrc::CartesianRange) - isempty(Rdest) && return dest - if size(Rdest) != size(Rsrc) - throw(ArgumentError("source and destination must have same size (got $(size(Rsrc)) and $(size(Rdest)))")) - end - @boundscheck checkbounds(dest, Rdest.start) - @boundscheck checkbounds(dest, Rdest.stop) - @boundscheck checkbounds(src, Rsrc.start) - @boundscheck checkbounds(src, Rsrc.stop) - deltaI = Rdest.start - Rsrc.start - for I in Rsrc - @inbounds dest[I+deltaI] = src[I] +@generated function copy!{T1,T2,N}(dest::AbstractArray{T1,N}, + Rdest::CartesianRange{CartesianIndex{N}}, + src::AbstractArray{T2,N}, + Rsrc::CartesianRange{CartesianIndex{N}}) + quote + isempty(Rdest) && return dest + if size(Rdest) != size(Rsrc) + throw(ArgumentError("source and destination must have same size (got $(size(Rsrc)) and $(size(Rdest)))")) + end + @boundscheck checkbounds(dest, Rdest.start) + @boundscheck checkbounds(dest, Rdest.stop) + @boundscheck checkbounds(src, Rsrc.start) + @boundscheck checkbounds(src, Rsrc.stop) + ΔI = Rdest.start - Rsrc.start + # for I in Rsrc + # @inbounds dest[I+ΔI] = src[I] + @nloops $N i (n->Rsrc.start[n]:Rsrc.stop[n]) begin + @inbounds @nref($N,dest,n->i_n+ΔI[n]) = @nref($N,src,i) + end + dest end - dest end """ diff --git a/test/copy.jl b/test/copy.jl index 015e3b3e507bf..2e48fc9912afe 100644 --- a/test/copy.jl +++ b/test/copy.jl @@ -48,6 +48,20 @@ for (dest, src, bigsrc, emptysrc, res) in [ @test_throws BoundsError copy!(dest, 1, src(), 2, 2) end +let A = reshape(1:6, 3, 2), B = similar(A) + RA = CartesianRange(indices(A)) + copy!(B, RA, A, RA) + @test B == A +end +let A = reshape(1:6, 3, 2), B = zeros(8,8) + RA = CartesianRange(indices(A)) + copy!(B, CartesianRange((5:7,2:3)), A, RA) + @test B[5:7,2:3] == A + B[5:7,2:3] = 0 + @test all(x->x==0, B) +end + + # test behavior of shallow and deep copying let a = Any[[1]], q = QuoteNode([1]) ca = copy(a); dca = @inferred(deepcopy(a)) @@ -128,4 +142,3 @@ end @test bar2.fooDict[bar2.foo] != nothing end end - From 9ceb52b14fb5f2ed7e165e31bcd3933703e505c5 Mon Sep 17 00:00:00 2001 From: JKrehl Date: Wed, 8 Mar 2017 11:06:22 -0600 Subject: [PATCH 3/4] Force inlining on CartesianIndex operations --- base/multidimensional.jl | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/base/multidimensional.jl b/base/multidimensional.jl index 8c5ce2ad155fd..f944d114b1072 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -65,22 +65,23 @@ module IteratorsMD one{N}(::Type{CartesianIndex{N}}) = CartesianIndex(ntuple(x -> 1, Val{N})) # arithmetic, min/max - (-){N}(index::CartesianIndex{N}) = CartesianIndex{N}(map(-, index.I)) - (+){N}(index1::CartesianIndex{N}, index2::CartesianIndex{N}) = + @inline (-){N}(index::CartesianIndex{N}) = + CartesianIndex{N}(map(-, index.I)) + @inline (+){N}(index1::CartesianIndex{N}, index2::CartesianIndex{N}) = CartesianIndex{N}(map(+, index1.I, index2.I)) - (-){N}(index1::CartesianIndex{N}, index2::CartesianIndex{N}) = + @inline (-){N}(index1::CartesianIndex{N}, index2::CartesianIndex{N}) = CartesianIndex{N}(map(-, index1.I, index2.I)) - min{N}(index1::CartesianIndex{N}, index2::CartesianIndex{N}) = + @inline min{N}(index1::CartesianIndex{N}, index2::CartesianIndex{N}) = CartesianIndex{N}(map(min, index1.I, index2.I)) - max{N}(index1::CartesianIndex{N}, index2::CartesianIndex{N}) = + @inline max{N}(index1::CartesianIndex{N}, index2::CartesianIndex{N}) = CartesianIndex{N}(map(max, index1.I, index2.I)) - (+)(i::Integer, index::CartesianIndex) = index+i - (+){N}(index::CartesianIndex{N}, i::Integer) = CartesianIndex{N}(map(x->x+i, index.I)) - (-){N}(index::CartesianIndex{N}, i::Integer) = CartesianIndex{N}(map(x->x-i, index.I)) - (-){N}(i::Integer, index::CartesianIndex{N}) = CartesianIndex{N}(map(x->i-x, index.I)) - (*){N}(a::Integer, index::CartesianIndex{N}) = CartesianIndex{N}(map(x->a*x, index.I)) - (*)(index::CartesianIndex,a::Integer)=*(a,index) + @inline (+)(i::Integer, index::CartesianIndex) = index+i + @inline (+){N}(index::CartesianIndex{N}, i::Integer) = CartesianIndex{N}(map(x->x+i, index.I)) + @inline (-){N}(index::CartesianIndex{N}, i::Integer) = CartesianIndex{N}(map(x->x-i, index.I)) + @inline (-){N}(i::Integer, index::CartesianIndex{N}) = CartesianIndex{N}(map(x->i-x, index.I)) + @inline (*){N}(a::Integer, index::CartesianIndex{N}) = CartesianIndex{N}(map(x->a*x, index.I)) + @inline (*)(index::CartesianIndex,a::Integer)=*(a,index) # comparison @inline isless{N}(I1::CartesianIndex{N}, I2::CartesianIndex{N}) = _isless(0, I1.I, I2.I) From b96ce3be2d8ba29a23ef0d079907eb5650bf0fbf Mon Sep 17 00:00:00 2001 From: Tim Holy Date: Wed, 8 Mar 2017 19:57:12 -0600 Subject: [PATCH 4/4] Add TODO upon fixing issue 9080 [ci skip] --- base/multidimensional.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/base/multidimensional.jl b/base/multidimensional.jl index f944d114b1072..9fd9d40837523 100644 --- a/base/multidimensional.jl +++ b/base/multidimensional.jl @@ -821,6 +821,7 @@ end @boundscheck checkbounds(src, Rsrc.start) @boundscheck checkbounds(src, Rsrc.stop) ΔI = Rdest.start - Rsrc.start + # TODO: restore when #9080 is fixed # for I in Rsrc # @inbounds dest[I+ΔI] = src[I] @nloops $N i (n->Rsrc.start[n]:Rsrc.stop[n]) begin