diff --git a/base/docs/helpdb/Base.jl b/base/docs/helpdb/Base.jl index d725d54390b6da..d5f9000b947beb 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 6e0b8a567b57f7..00b8ff762d07bc 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,11 @@ function fill!{T}(A::AbstractArray{T}, x) A end +""" + copy!(dest, src) -> dest + +Copy all elements from collection `src` to array `dest`. +""" 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) @@ -789,6 +804,12 @@ function copy!{T,N}(dest::AbstractArray{T,N}, src::AbstractArray{T,N}) 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. +""" function copy!(dest::AbstractArray, Rdest::CartesianRange, src::AbstractArray, Rsrc::CartesianRange) isempty(Rdest) && return dest if size(Rdest) != size(Rsrc) @@ -798,9 +819,16 @@ function copy!(dest::AbstractArray, Rdest::CartesianRange, src::AbstractArray, R @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] + ΔI = Rdest.start - Rsrc.start + # For reasons of performance, split out the first dimension + ΔI1, ΔItail = IteratorsMD.split(ΔI, Val{1}) + R1, Rtail = IteratorsMD.split(Rsrc, Val{1}) + Δi, r1 = ΔI1[1], convert(Tuple{UnitRange}, R1)[1] + for I in Rtail + Idest = I+ΔItail + for i in r1 + @inbounds dest[i+Δi, Idest] = src[i, I] + end end dest end diff --git a/doc/src/stdlib/arrays.md b/doc/src/stdlib/arrays.md index 0e097e7bb71a7a..87c06ac591ebb8 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 diff --git a/test/copy.jl b/test/copy.jl index 015e3b3e507bf7..2e48fc9912afe6 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 -