Skip to content

Commit 0ea2b2d

Browse files
authored
copyto! fix for BitArray/AbstractArray, fixes #25968 (#46161)
1. map `copyto!(::BitArray, n1, ::BitArray, n2, l)` to `Base.unsafe_copyto!` 2. add missing unaliasing in `copyto!` for `AbstractArray`
1 parent 1addb84 commit 0ea2b2d

File tree

4 files changed

+23
-13
lines changed

4 files changed

+23
-13
lines changed

base/abstractarray.jl

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -891,13 +891,12 @@ See also [`copyto!`](@ref).
891891
is available from the `Future` standard library as `Future.copy!`.
892892
"""
893893
function copy!(dst::AbstractVector, src::AbstractVector)
894+
firstindex(dst) == firstindex(src) || throw(ArgumentError(
895+
"vectors must have the same offset for copy! (consider using `copyto!`)"))
894896
if length(dst) != length(src)
895897
resize!(dst, length(src))
896898
end
897-
for i in eachindex(dst, src)
898-
@inbounds dst[i] = src[i]
899-
end
900-
dst
899+
copyto!(dst, src)
901900
end
902901

903902
function copy!(dst::AbstractArray, src::AbstractArray)
@@ -1108,8 +1107,9 @@ function copyto!(dest::AbstractArray, dstart::Integer,
11081107
destinds, srcinds = LinearIndices(dest), LinearIndices(src)
11091108
(checkbounds(Bool, destinds, dstart) && checkbounds(Bool, destinds, dstart+n-1)) || throw(BoundsError(dest, dstart:dstart+n-1))
11101109
(checkbounds(Bool, srcinds, sstart) && checkbounds(Bool, srcinds, sstart+n-1)) || throw(BoundsError(src, sstart:sstart+n-1))
1111-
@inbounds for i = 0:(n-1)
1112-
dest[dstart+i] = src[sstart+i]
1110+
src′ = unalias(dest, src)
1111+
@inbounds for i = 0:n-1
1112+
dest[dstart+i] = src′[sstart+i]
11131113
end
11141114
return dest
11151115
end
@@ -1131,11 +1131,12 @@ function copyto!(B::AbstractVecOrMat{R}, ir_dest::AbstractRange{Int}, jr_dest::A
11311131
end
11321132
@boundscheck checkbounds(B, ir_dest, jr_dest)
11331133
@boundscheck checkbounds(A, ir_src, jr_src)
1134+
A′ = unalias(B, A)
11341135
jdest = first(jr_dest)
11351136
for jsrc in jr_src
11361137
idest = first(ir_dest)
11371138
for isrc in ir_src
1138-
@inbounds B[idest,jdest] = A[isrc,jsrc]
1139+
@inbounds B[idest,jdest] = A[isrc,jsrc]
11391140
idest += step(ir_dest)
11401141
end
11411142
jdest += step(jr_dest)

base/bitarray.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -458,10 +458,11 @@ function unsafe_copyto!(dest::BitArray, doffs::Integer, src::Union{BitArray,Arra
458458
return dest
459459
end
460460

461-
copyto!(dest::BitArray, doffs::Integer, src::Array, soffs::Integer, n::Integer) =
461+
copyto!(dest::BitArray, doffs::Integer, src::Union{BitArray,Array}, soffs::Integer, n::Integer) =
462462
_copyto_int!(dest, Int(doffs), src, Int(soffs), Int(n))
463-
function _copyto_int!(dest::BitArray, doffs::Int, src::Array, soffs::Int, n::Int)
463+
function _copyto_int!(dest::BitArray, doffs::Int, src::Union{BitArray,Array}, soffs::Int, n::Int)
464464
n == 0 && return dest
465+
n < 0 && throw(ArgumentError("Number of elements to copy must be nonnegative."))
465466
soffs < 1 && throw(BoundsError(src, soffs))
466467
doffs < 1 && throw(BoundsError(dest, doffs))
467468
soffs+n-1 > length(src) && throw(BoundsError(src, length(src)+1))

test/bitarray.jl

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,11 @@ bitcheck(x) = true
1515
bcast_setindex!(b, x, I...) = (b[I...] .= x; b)
1616

1717
function check_bitop_call(ret_type, func, args...; kwargs...)
18-
r1 = func(args...; kwargs...)
1918
r2 = func(map(x->(isa(x, BitArray) ? Array(x) : x), args)...; kwargs...)
20-
ret_type nothing && !isa(r1, ret_type) && @show ret_type, typeof(r1)
21-
ret_type nothing && @test isa(r1, ret_type)
19+
r1 = func(args...; kwargs...)
20+
ret_type nothing && (@test isa(r1, ret_type) || @show ret_type, typeof(r1))
2221
@test tc(r1, r2)
23-
@test isequal(r1, ret_type nothing ? r2 : r2)
22+
@test isequal(r1, r2)
2423
@test bitcheck(r1)
2524
end
2625
macro check_bit_operation(ex, ret_type)
@@ -518,12 +517,14 @@ timesofar("constructors")
518517
end
519518
end
520519

520+
self_copyto!(a, n1, n2, l) = copyto!(a, n1, a, n2, l)
521521
for p1 = [rand(1:v1) 1 63 64 65 191 192 193]
522522
for p2 = [rand(1:v1) 1 63 64 65 191 192 193]
523523
for n = 0 : min(v1 - p1 + 1, v1 - p2 + 1)
524524
b1 = bitrand(v1)
525525
b2 = bitrand(v1)
526526
@check_bit_operation copyto!(b1, p1, b2, p2, n) BitVector
527+
@check_bit_operation self_copyto!(b1, p1, p2, n) BitVector
527528
end
528529
end
529530
end

test/copy.jl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,3 +245,10 @@ end
245245
@testset "deepcopy_internal arrays" begin
246246
@test (@inferred Base.deepcopy_internal(zeros(), IdDict())) == zeros()
247247
end
248+
249+
@testset "`copyto!`'s unaliasing" begin
250+
a = view([1:3;], :)
251+
@test copyto!(a, 2, a, 1, 2) == [1;1:2;]
252+
a = [1:3;]
253+
@test copyto!(a, 2:3, 1:1, a, 1:2, 1:1) == [1;1:2;]
254+
end

0 commit comments

Comments
 (0)