Skip to content

Commit 8a4eb38

Browse files
committed
fix #45825, BitArray methods assuming 1-indexing of AbstractArray
1 parent 84bf42a commit 8a4eb38

File tree

3 files changed

+62
-26
lines changed

3 files changed

+62
-26
lines changed

base/abstractarray.jl

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,6 +1035,10 @@ julia> y
10351035
"""
10361036
function copyto!(dest::AbstractArray, src::AbstractArray)
10371037
isempty(src) && return dest
1038+
if dest isa BitArray
1039+
# avoid ambiguities with other copyto!(::AbstractArray, ::SourceArray) methods
1040+
return _copyto_bitarray!(dest, src)
1041+
end
10381042
src′ = unalias(dest, src)
10391043
copyto_unaliased!(IndexStyle(dest), dest, IndexStyle(src′), src′)
10401044
end
@@ -1139,10 +1143,10 @@ function copyto!(B::AbstractVecOrMat{R}, ir_dest::AbstractRange{Int}, jr_dest::A
11391143
return B
11401144
end
11411145

1142-
function copyto_axcheck!(dest, src)
1143-
@noinline checkaxs(axd, axs) = axd == axs || throw(DimensionMismatch("axes must agree, got $axd and $axs"))
1146+
@noinline _checkaxs(axd, axs) = axd == axs || throw(DimensionMismatch("axes must agree, got $axd and $axs"))
11441147

1145-
checkaxs(axes(dest), axes(src))
1148+
function copyto_axcheck!(dest, src)
1149+
_checkaxs(axes(dest), axes(src))
11461150
copyto!(dest, src)
11471151
end
11481152

base/bitarray.jl

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -501,40 +501,40 @@ function Array{T,N}(B::BitArray{N}) where {T,N}
501501
end
502502

503503
BitArray(A::AbstractArray{<:Any,N}) where {N} = BitArray{N}(A)
504+
504505
function BitArray{N}(A::AbstractArray{T,N}) where N where T
505506
B = BitArray(undef, convert(Dims{N}, size(A)::Dims{N}))
506-
Bc = B.chunks
507-
l = length(B)
507+
_checkaxs(axes(B), axes(A))
508+
_copyto_bitarray!(B, A)
509+
return B::BitArray{N}
510+
end
511+
512+
function _copyto_bitarray!(B::BitArray, A::AbstractArray)
513+
l = length(A)
508514
l == 0 && return B
509-
ind = 1
515+
l > length(B) && throw(BoundsError(B, length(B)+1))
516+
Bc = B.chunks
517+
nc = num_bit_chunks(l)
518+
Ai = first(eachindex(A))
510519
@inbounds begin
511-
for i = 1:length(Bc)-1
520+
for i = 1:nc-1
512521
c = UInt64(0)
513522
for j = 0:63
514-
c |= (UInt64(convert(Bool, A[ind])::Bool) << j)
515-
ind += 1
523+
c |= (UInt64(convert(Bool, A[Ai])::Bool) << j)
524+
Ai = nextind(A, Ai)
516525
end
517526
Bc[i] = c
518527
end
519528
c = UInt64(0)
520529
for j = 0:_mod64(l-1)
521-
c |= (UInt64(convert(Bool, A[ind])::Bool) << j)
522-
ind += 1
530+
c |= (UInt64(convert(Bool, A[Ai])::Bool) << j)
531+
Ai = nextind(A, Ai)
523532
end
524533
Bc[end] = c
525534
end
526535
return B
527536
end
528537

529-
function BitArray{N}(A::Array{Bool,N}) where N
530-
B = BitArray(undef, size(A))
531-
Bc = B.chunks
532-
l = length(B)
533-
l == 0 && return B
534-
copy_to_bitarray_chunks!(Bc, 1, A, 1, l)
535-
return B::BitArray{N}
536-
end
537-
538538
reinterpret(::Type{Bool}, B::BitArray, dims::NTuple{N,Int}) where {N} = reinterpret(B, dims)
539539
reinterpret(B::BitArray, dims::NTuple{N,Int}) where {N} = reshape(B, dims)
540540

@@ -721,24 +721,25 @@ function _unsafe_setindex!(B::BitArray, X::AbstractArray, I::BitArray)
721721
lx = length(X)
722722
last_chunk_len = _mod64(length(B)-1)+1
723723

724-
c = 1
724+
Xi = first(eachindex(X))
725+
lastXi = last(eachindex(X))
725726
for i = 1:lc
726727
@inbounds Imsk = Ic[i]
727728
@inbounds C = Bc[i]
728729
u = UInt64(1)
729730
for j = 1:(i < lc ? 64 : last_chunk_len)
730731
if Imsk & u != 0
731-
lx < c && throw_setindex_mismatch(X, c)
732-
@inbounds x = convert(Bool, X[c])
732+
Xi > lastXi && throw_setindex_mismatch(X, count(I))
733+
@inbounds x = convert(Bool, X[Xi])
733734
C = ifelse(x, C | u, C & ~u)
734-
c += 1
735+
Xi = nextind(X, Xi)
735736
end
736737
u <<= 1
737738
end
738739
@inbounds Bc[i] = C
739740
end
740-
if length(X) != c-1
741-
throw_setindex_mismatch(X, c-1)
741+
if Xi != nextind(X, lastXi)
742+
throw_setindex_mismatch(X, count(I))
742743
end
743744
return B
744745
end

test/bitarray.jl

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1787,3 +1787,34 @@ end
17871787
@test all(bitarray[rangein, rangeout] .== true)
17881788
end
17891789
end
1790+
1791+
# issue #45825
1792+
1793+
isdefined(Main, :OffsetArrays) || @eval Main include("testhelpers/OffsetArrays.jl")
1794+
using .Main.OffsetArrays
1795+
1796+
let all_false = OffsetArray(falses(2001), -1000:1000)
1797+
@test !any(==(true), all_false)
1798+
# should be run with --check-bounds=yes
1799+
@test_throws DimensionMismatch BitArray(all_false)
1800+
all_false = OffsetArray(falses(2001), 1:2001)
1801+
@test !any(==(true), BitArray(all_false))
1802+
all_false = OffsetArray(falses(100, 100), 0:99, -1:98)
1803+
@test !any(==(true), all_false)
1804+
@test_throws DimensionMismatch BitArray(all_false)
1805+
all_false = OffsetArray(falses(100, 100), 1:100, 1:100)
1806+
@test !any(==(true), all_false)
1807+
end
1808+
let a = falses(1000),
1809+
msk = BitArray(rand(Bool, 1000)),
1810+
n = count(msk),
1811+
b = OffsetArray(rand(Bool, n), (-n÷2):(n÷2)-iseven(n))
1812+
a[msk] = b
1813+
@test a[msk] == collect(b)
1814+
a = falses(100, 100)
1815+
msk = BitArray(rand(Bool, 100, 100))
1816+
n = count(msk)
1817+
b = OffsetArray(rand(Bool, 1, n), 1:1, (-n÷2):(n÷2)-iseven(n))
1818+
a[msk] = b
1819+
@test a[msk] == vec(collect(b))
1820+
end

0 commit comments

Comments
 (0)