Skip to content

Commit e91065c

Browse files
authored
Merge pull request #20944 from JuliaLang/teh/faster_copyR
Speed up copy!(dest, Rdest, src, Rsrc) by splitting out first dimension
2 parents 3b5a0eb + b96ce3b commit e91065c

File tree

4 files changed

+73
-32
lines changed

4 files changed

+73
-32
lines changed

base/docs/helpdb/Base.jl

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2027,13 +2027,6 @@ algorithms. See [`muladd`](@ref).
20272027
"""
20282028
fma
20292029

2030-
"""
2031-
copy!(dest, src)
2032-
2033-
Copy all elements from collection `src` to array `dest`. Returns `dest`.
2034-
"""
2035-
copy!(dest,src)
2036-
20372030
"""
20382031
copy!(dest, do, src, so, N)
20392032

base/multidimensional.jl

Lines changed: 58 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -65,22 +65,23 @@ module IteratorsMD
6565
one{N}(::Type{CartesianIndex{N}}) = CartesianIndex(ntuple(x -> 1, Val{N}))
6666

6767
# arithmetic, min/max
68-
(-){N}(index::CartesianIndex{N}) = CartesianIndex{N}(map(-, index.I))
69-
(+){N}(index1::CartesianIndex{N}, index2::CartesianIndex{N}) =
68+
@inline (-){N}(index::CartesianIndex{N}) =
69+
CartesianIndex{N}(map(-, index.I))
70+
@inline (+){N}(index1::CartesianIndex{N}, index2::CartesianIndex{N}) =
7071
CartesianIndex{N}(map(+, index1.I, index2.I))
71-
(-){N}(index1::CartesianIndex{N}, index2::CartesianIndex{N}) =
72+
@inline (-){N}(index1::CartesianIndex{N}, index2::CartesianIndex{N}) =
7273
CartesianIndex{N}(map(-, index1.I, index2.I))
73-
min{N}(index1::CartesianIndex{N}, index2::CartesianIndex{N}) =
74+
@inline min{N}(index1::CartesianIndex{N}, index2::CartesianIndex{N}) =
7475
CartesianIndex{N}(map(min, index1.I, index2.I))
75-
max{N}(index1::CartesianIndex{N}, index2::CartesianIndex{N}) =
76+
@inline max{N}(index1::CartesianIndex{N}, index2::CartesianIndex{N}) =
7677
CartesianIndex{N}(map(max, index1.I, index2.I))
7778

78-
(+)(i::Integer, index::CartesianIndex) = index+i
79-
(+){N}(index::CartesianIndex{N}, i::Integer) = CartesianIndex{N}(map(x->x+i, index.I))
80-
(-){N}(index::CartesianIndex{N}, i::Integer) = CartesianIndex{N}(map(x->x-i, index.I))
81-
(-){N}(i::Integer, index::CartesianIndex{N}) = CartesianIndex{N}(map(x->i-x, index.I))
82-
(*){N}(a::Integer, index::CartesianIndex{N}) = CartesianIndex{N}(map(x->a*x, index.I))
83-
(*)(index::CartesianIndex,a::Integer)=*(a,index)
79+
@inline (+)(i::Integer, index::CartesianIndex) = index+i
80+
@inline (+){N}(index::CartesianIndex{N}, i::Integer) = CartesianIndex{N}(map(x->x+i, index.I))
81+
@inline (-){N}(index::CartesianIndex{N}, i::Integer) = CartesianIndex{N}(map(x->x-i, index.I))
82+
@inline (-){N}(i::Integer, index::CartesianIndex{N}) = CartesianIndex{N}(map(x->i-x, index.I))
83+
@inline (*){N}(a::Integer, index::CartesianIndex{N}) = CartesianIndex{N}(map(x->a*x, index.I))
84+
@inline (*)(index::CartesianIndex,a::Integer)=*(a,index)
8485

8586
# comparison
8687
@inline isless{N}(I1::CartesianIndex{N}, I2::CartesianIndex{N}) = _isless(0, I1.I, I2.I)
@@ -209,6 +210,16 @@ module IteratorsMD
209210
@inline _split{N}(tN::NTuple{N,Any}, ::Tuple{}, ::Type{Val{N}}) = tN, () # ambig.
210211
@inline _split{N}(tN, ::Tuple{}, ::Type{Val{N}}) = tN, ()
211212
@inline _split{N}(tN::NTuple{N,Any}, trest, ::Type{Val{N}}) = tN, trest
213+
214+
@inline function split(I::CartesianIndex, V::Type{<:Val})
215+
i, j = split(I.I, V)
216+
CartesianIndex(i), CartesianIndex(j)
217+
end
218+
function split(R::CartesianRange, V::Type{<:Val})
219+
istart, jstart = split(first(R), V)
220+
istop, jstop = split(last(R), V)
221+
CartesianRange(istart, istop), CartesianRange(jstart, jstop)
222+
end
212223
end # IteratorsMD
213224

214225

@@ -781,6 +792,13 @@ function fill!{T}(A::AbstractArray{T}, x)
781792
A
782793
end
783794

795+
"""
796+
copy!(dest, src) -> dest
797+
798+
Copy all elements from collection `src` to array `dest`.
799+
"""
800+
copy!(dest, src)
801+
784802
function copy!{T,N}(dest::AbstractArray{T,N}, src::AbstractArray{T,N})
785803
@boundscheck checkbounds(dest, indices(src)...)
786804
for I in eachindex(IndexStyle(src,dest), src)
@@ -789,22 +807,38 @@ function copy!{T,N}(dest::AbstractArray{T,N}, src::AbstractArray{T,N})
789807
dest
790808
end
791809

792-
function copy!(dest::AbstractArray, Rdest::CartesianRange, src::AbstractArray, Rsrc::CartesianRange)
793-
isempty(Rdest) && return dest
794-
if size(Rdest) != size(Rsrc)
795-
throw(ArgumentError("source and destination must have same size (got $(size(Rsrc)) and $(size(Rdest)))"))
796-
end
797-
@boundscheck checkbounds(dest, Rdest.start)
798-
@boundscheck checkbounds(dest, Rdest.stop)
799-
@boundscheck checkbounds(src, Rsrc.start)
800-
@boundscheck checkbounds(src, Rsrc.stop)
801-
deltaI = Rdest.start - Rsrc.start
802-
for I in Rsrc
803-
@inbounds dest[I+deltaI] = src[I]
810+
@generated function copy!{T1,T2,N}(dest::AbstractArray{T1,N},
811+
Rdest::CartesianRange{CartesianIndex{N}},
812+
src::AbstractArray{T2,N},
813+
Rsrc::CartesianRange{CartesianIndex{N}})
814+
quote
815+
isempty(Rdest) && return dest
816+
if size(Rdest) != size(Rsrc)
817+
throw(ArgumentError("source and destination must have same size (got $(size(Rsrc)) and $(size(Rdest)))"))
818+
end
819+
@boundscheck checkbounds(dest, Rdest.start)
820+
@boundscheck checkbounds(dest, Rdest.stop)
821+
@boundscheck checkbounds(src, Rsrc.start)
822+
@boundscheck checkbounds(src, Rsrc.stop)
823+
ΔI = Rdest.start - Rsrc.start
824+
# TODO: restore when #9080 is fixed
825+
# for I in Rsrc
826+
# @inbounds dest[I+ΔI] = src[I]
827+
@nloops $N i (n->Rsrc.start[n]:Rsrc.stop[n]) begin
828+
@inbounds @nref($N,dest,n->i_n+ΔI[n]) = @nref($N,src,i)
829+
end
830+
dest
804831
end
805-
dest
806832
end
807833

834+
"""
835+
copy!(dest, Rdest::CartesianRange, src, Rsrc::CartesianRange) -> dest
836+
837+
Copy the block of `src` in the range of `Rsrc` to the block of `dest`
838+
in the range of `Rdest`. The sizes of the two regions must match.
839+
"""
840+
copy!(::AbstractArray, ::CartesianRange, ::AbstractArray, ::CartesianRange)
841+
808842
# circshift!
809843
circshift!(dest::AbstractArray, src, ::Tuple{}) = copy!(dest, src)
810844
"""

doc/src/stdlib/arrays.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ Base.Broadcast.broadcast_setindex!
6161
```@docs
6262
Base.getindex(::AbstractArray, ::Any...)
6363
Base.setindex!(::AbstractArray, ::Any, ::Any...)
64+
Base.copy!(::AbstractArray, ::CartesianRange, ::AbstractArray, ::CartesianRange)
6465
Base.isassigned
6566
Base.Colon
6667
Base.CartesianIndex

test/copy.jl

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,20 @@ for (dest, src, bigsrc, emptysrc, res) in [
4848
@test_throws BoundsError copy!(dest, 1, src(), 2, 2)
4949
end
5050

51+
let A = reshape(1:6, 3, 2), B = similar(A)
52+
RA = CartesianRange(indices(A))
53+
copy!(B, RA, A, RA)
54+
@test B == A
55+
end
56+
let A = reshape(1:6, 3, 2), B = zeros(8,8)
57+
RA = CartesianRange(indices(A))
58+
copy!(B, CartesianRange((5:7,2:3)), A, RA)
59+
@test B[5:7,2:3] == A
60+
B[5:7,2:3] = 0
61+
@test all(x->x==0, B)
62+
end
63+
64+
5165
# test behavior of shallow and deep copying
5266
let a = Any[[1]], q = QuoteNode([1])
5367
ca = copy(a); dca = @inferred(deepcopy(a))
@@ -128,4 +142,3 @@ end
128142
@test bar2.fooDict[bar2.foo] != nothing
129143
end
130144
end
131-

0 commit comments

Comments
 (0)