Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 30 additions & 12 deletions base/abstractarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1076,25 +1076,22 @@ function copyto!(deststyle::IndexStyle, dest::AbstractArray, srcstyle::IndexStyl
copyto_unaliased!(deststyle, dest, srcstyle, src′)
end

function copyto_unaliased!(deststyle::IndexStyle, dest::AbstractArray, srcstyle::IndexStyle, src::AbstractArray)
function copyto_unaliased!(::IndexLinear, dest::AbstractArray, ::IndexLinear, src::AbstractArray)
copyto!(dest, first(LinearIndices(dest)), src, first(LinearIndices(src)), length(src))
end
function copyto_unaliased!(deststyle::IndexStyle, dest::AbstractArray, ::IndexStyle, src::AbstractArray)
isempty(src) && return dest
destinds, srcinds = LinearIndices(dest), LinearIndices(src)
idf, isf = first(destinds), first(srcinds)
Δi = idf - isf
(checkbounds(Bool, destinds, isf+Δi) & checkbounds(Bool, destinds, last(srcinds)+Δi)) ||
throw(BoundsError(dest, srcinds))
if deststyle isa IndexLinear
if srcstyle isa IndexLinear
# Single-index implementation
@inbounds for i in srcinds
dest[i + Δi] = src[i]
end
else
# Dual-index implementation
i = idf - 1
@inbounds for a in src
dest[i+=1] = a
end
# IndexStyle(src) is IndexCartesian, as the linear indexing case is handled separately
# Dual-index implementation
i = idf - 1
@inbounds for a in src
dest[i+=1] = a
end
else
iterdest, itersrc = eachindex(dest), eachindex(src)
Expand Down Expand Up @@ -1123,7 +1120,28 @@ function copyto!(dest::AbstractArray, dstart::Integer, src::AbstractArray, sstar
copyto!(dest, dstart, src, sstart, last(srcinds)-sstart+1)
end

# we add an extra level of indirection to forward the copy
# to the parent for contiguous linear views
function copyto!(dest::AbstractArray, dstart::Integer,
src::AbstractArray, sstart::Integer, n::Integer)
# check if the arrays are views that may be unwrapped
# if yes, try to use the copyto! implementation for the parents
# if no, then fall back to the default implementation that loops over the arrays
__copyto!(dest, _unwrap_view(dest, dstart)..., src, _unwrap_view(src, sstart)..., n)
end
# `_unwrap_view` potentially unwraps a SubArray and shifts the index `ind` by the linear offset of the view
# If the array `A` is not a view, there's nothing to unwrap
_unwrap_view(A, ind) = A, ind
# fallback method if neither array is a SubArray, in which case we loop over them
function __copyto!(dest::A, ::A, dstart, src::B, ::B, sstart, n) where {A,B}
_copyto!(dest, dstart, src, sstart, n)
end
# Forward the copy to the parent if there is any contiguous, linearly indexed view
function __copyto!(_, destp, dstart, _, srcp, sstart, n)
copyto!(destp, dstart, srcp, sstart, n)
end

function _copyto!(dest::AbstractArray, dstart::Integer,
src::AbstractArray, sstart::Integer,
n::Integer)
n == 0 && return dest
Expand Down
6 changes: 3 additions & 3 deletions base/sort.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1955,12 +1955,12 @@ function sortperm(A::AbstractArray;
scratch::Union{Vector{<:Integer}, Nothing}=nothing,
dims...) #to optionally specify dims argument
if rev === true
_sortperm(A; alg, order=ord(lt, by, true, order), scratch, dims...)
_sortperm(A, alg, ord(lt, by, true, order), scratch, dims)
else
_sortperm(A; alg, order=ord(lt, by, nothing, order), scratch, dims...)
_sortperm(A, alg, ord(lt, by, nothing, order), scratch, dims)
end
end
function _sortperm(A::AbstractArray; alg, order, scratch, dims...)
function _sortperm(A::AbstractArray, alg, order, scratch, dims)
if order === Forward && isa(A,Vector) && eltype(A)<:Integer
n = length(A)
if n > 1
Expand Down
4 changes: 4 additions & 0 deletions base/subarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,10 @@ FastContiguousSubArray{T,N,P,I<:Union{Tuple{AbstractUnitRange, Vararg{Any}},
@inline _reindexlinear(V::FastContiguousSubArray, i::Int) = V.offset1 + i
@inline _reindexlinear(V::FastContiguousSubArray, i::AbstractUnitRange{Int}) = V.offset1 .+ i

# we may forward the 5-term copyto! for contiguous linearly indexed views to the corresponding parents
# this lets us access optimized copyto! implementations for the parent
_unwrap_view(A::FastContiguousSubArray, Astart) = parent(A), A.offset1 + Astart

"""
An internal type representing arrays stored contiguously in memory.
"""
Expand Down
25 changes: 25 additions & 0 deletions test/subarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1098,3 +1098,28 @@ end
@test Base.mightalias(permutedims(V1), V1)
@test Base.mightalias(permutedims(V1), permutedims(V1))
end

@testset "copyto! with linearly indexed views" begin
@testset "FastContiguousSubArray" begin
A = rand(4)
vA = view(A, :)
B = zeros(4)
vB = view(B, :)
for y in (B, vB), x in (A, vA)
y .= 0
copyto!(y, x)
@test y == x
end
end
@testset "FastSubArray" begin
A = rand(4)
vA = @view A[1:2:end]
B = zeros(4)
vB = @view B[1:2:end]
@test copyto!(vB, vA) == vA
B .= 0
@test copyto!(B, vA)[axes(vA,1)] == vA
B .= 0
@test copyto!(vB, 1, A, 1, 2) == view(A, 1:2)
end
end