Skip to content

Commit 4d22bb2

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

File tree

3 files changed

+53
-23
lines changed

3 files changed

+53
-23
lines changed

base/abstractarray.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1139,10 +1139,10 @@ function copyto!(B::AbstractVecOrMat{R}, ir_dest::AbstractRange{Int}, jr_dest::A
11391139
return B
11401140
end
11411141

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

1145-
checkaxs(axes(dest), axes(src))
1144+
function copyto_axcheck!(dest, src)
1145+
_checkaxs(axes(dest), axes(src))
11461146
copyto!(dest, src)
11471147
end
11481148

base/bitarray.jl

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -501,40 +501,38 @@ 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}))
507+
_checkaxs(axes(B), axes(A))
508+
copyto!(B, A)
509+
return B::BitArray{N}
510+
end
511+
512+
function copyto!(B::BitArray, A::AbstractArray)
506513
Bc = B.chunks
507514
l = length(B)
508515
l == 0 && return B
509-
ind = 1
516+
Ai = first(eachindex(A))
510517
@inbounds begin
511518
for i = 1:length(Bc)-1
512519
c = UInt64(0)
513520
for j = 0:63
514-
c |= (UInt64(convert(Bool, A[ind])::Bool) << j)
515-
ind += 1
521+
c |= (UInt64(convert(Bool, A[Ai])::Bool) << j)
522+
Ai = nextind(A, Ai)
516523
end
517524
Bc[i] = c
518525
end
519526
c = UInt64(0)
520527
for j = 0:_mod64(l-1)
521-
c |= (UInt64(convert(Bool, A[ind])::Bool) << j)
522-
ind += 1
528+
c |= (UInt64(convert(Bool, A[Ai])::Bool) << j)
529+
Ai = nextind(A, Ai)
523530
end
524531
Bc[end] = c
525532
end
526533
return B
527534
end
528535

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-
538536
reinterpret(::Type{Bool}, B::BitArray, dims::NTuple{N,Int}) where {N} = reinterpret(B, dims)
539537
reinterpret(B::BitArray, dims::NTuple{N,Int}) where {N} = reshape(B, dims)
540538

@@ -721,24 +719,25 @@ function _unsafe_setindex!(B::BitArray, X::AbstractArray, I::BitArray)
721719
lx = length(X)
722720
last_chunk_len = _mod64(length(B)-1)+1
723721

724-
c = 1
722+
Xi = first(eachindex(X))
723+
lastXi = last(eachindex(X))
725724
for i = 1:lc
726725
@inbounds Imsk = Ic[i]
727726
@inbounds C = Bc[i]
728727
u = UInt64(1)
729728
for j = 1:(i < lc ? 64 : last_chunk_len)
730729
if Imsk & u != 0
731-
lx < c && throw_setindex_mismatch(X, c)
732-
@inbounds x = convert(Bool, X[c])
730+
Xi > lastXi && throw_setindex_mismatch(X, count(I))
731+
@inbounds x = convert(Bool, X[Xi])
733732
C = ifelse(x, C | u, C & ~u)
734-
c += 1
733+
Xi = nextind(X, Xi)
735734
end
736735
u <<= 1
737736
end
738737
@inbounds Bc[i] = C
739738
end
740-
if length(X) != c-1
741-
throw_setindex_mismatch(X, c-1)
739+
if Xi != nextind(X, lastXi)
740+
throw_setindex_mismatch(X, count(I))
742741
end
743742
return B
744743
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)