Skip to content

Commit deb3fac

Browse files
bkaminsdkarrasch
andauthored
Improve corner cases of deleteat! (#42144)
Co-authored-by: Daniel Karrasch <daniel.karrasch@posteo.de>
1 parent 1e6c269 commit deb3fac

File tree

3 files changed

+103
-6
lines changed

3 files changed

+103
-6
lines changed

base/array.jl

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1479,12 +1479,22 @@ julia> deleteat!([6, 5, 4, 3, 2, 1], 2)
14791479
1
14801480
```
14811481
"""
1482-
deleteat!(a::Vector, i::Integer) = (_deleteat!(a, i, 1); a)
1482+
function deleteat!(a::Vector, i::Integer)
1483+
i isa Bool && depwarn("passing Bool as an index is deprecated", :deleteat!)
1484+
_deleteat!(a, i, 1)
1485+
return a
1486+
end
14831487

14841488
function deleteat!(a::Vector, r::AbstractUnitRange{<:Integer})
1485-
n = length(a)
1486-
isempty(r) || _deleteat!(a, first(r), length(r))
1487-
return a
1489+
if eltype(r) === Bool
1490+
return invoke(deleteat!, Tuple{Vector, AbstractVector{Bool}}, a, r)
1491+
else
1492+
n = length(a)
1493+
f = first(r)
1494+
f isa Bool && depwarn("passing Bool as an index is deprecated", :deleteat!)
1495+
isempty(r) || _deleteat!(a, f, length(r))
1496+
return a
1497+
end
14881498
end
14891499

14901500
"""

base/bitarray.jl

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -947,6 +947,7 @@ function _deleteat!(B::BitVector, i::Int)
947947
end
948948

949949
function deleteat!(B::BitVector, i::Integer)
950+
i isa Bool && depwarn("passing Bool as an index is deprecated", :deleteat!)
950951
i = Int(i)
951952
n = length(B)
952953
1 <= i <= n || throw(BoundsError(B, i))
@@ -987,25 +988,68 @@ function deleteat!(B::BitVector, inds)
987988

988989
(p, s) = y
989990
checkbounds(B, p)
991+
p isa Bool && throw(ArgumentError("invalid index $p of type Bool"))
990992
q = p+1
991993
new_l -= 1
992994
y = iterate(inds, s)
993995
while y !== nothing
994996
(i, s) = y
995997
if !(q <= i <= n)
998+
i isa Bool && throw(ArgumentError("invalid index $i of type Bool"))
996999
i < q && throw(ArgumentError("indices must be unique and sorted"))
9971000
throw(BoundsError(B, i))
9981001
end
9991002
new_l -= 1
10001003
if i > q
1001-
copy_chunks!(Bc, p, Bc, Int(q), Int(i-q))
1004+
copy_chunks!(Bc, Int(p), Bc, Int(q), Int(i-q))
10021005
p += i-q
10031006
end
10041007
q = i+1
10051008
y = iterate(inds, s)
10061009
end
10071010

1008-
q <= n && copy_chunks!(Bc, p, Bc, Int(q), Int(n-q+1))
1011+
q <= n && copy_chunks!(Bc, Int(p), Bc, Int(q), Int(n-q+1))
1012+
1013+
delta_k = num_bit_chunks(new_l) - length(Bc)
1014+
delta_k < 0 && _deleteend!(Bc, -delta_k)
1015+
1016+
B.len = new_l
1017+
1018+
if new_l > 0
1019+
Bc[end] &= _msk_end(new_l)
1020+
end
1021+
1022+
return B
1023+
end
1024+
1025+
function deleteat!(B::BitVector, inds::AbstractVector{Bool})
1026+
length(inds) == length(B) || throw(BoundsError(B, inds))
1027+
1028+
n = new_l = length(B)
1029+
y = findfirst(inds)
1030+
y === nothing && return B
1031+
1032+
Bc = B.chunks
1033+
1034+
p = y
1035+
s = y + 1
1036+
checkbounds(B, p)
1037+
q = p + 1
1038+
new_l -= 1
1039+
y = findnext(inds, s)
1040+
while y !== nothing
1041+
i = y
1042+
s = y + 1
1043+
new_l -= 1
1044+
if i > q
1045+
copy_chunks!(Bc, Int(p), Bc, Int(q), Int(i-q))
1046+
p += i - q
1047+
end
1048+
q = i + 1
1049+
y = findnext(inds, s)
1050+
end
1051+
1052+
q <= n && copy_chunks!(Bc, Int(p), Bc, Int(q), Int(n - q + 1))
10091053

10101054
delta_k = num_bit_chunks(new_l) - length(Bc)
10111055
delta_k < 0 && _deleteend!(Bc, -delta_k)
@@ -1020,6 +1064,10 @@ function deleteat!(B::BitVector, inds)
10201064
end
10211065

10221066
function splice!(B::BitVector, i::Integer)
1067+
# TODO: after deprecation remove the four lines below
1068+
# as v = B[i] is enough to do both bounds checking
1069+
# and Bool check then just pass Int(i) to _deleteat!
1070+
i isa Bool && depwarn("passing Bool as an index is deprecated", :splice!)
10231071
i = Int(i)
10241072
n = length(B)
10251073
1 <= i <= n || throw(BoundsError(B, i))
@@ -1032,8 +1080,10 @@ end
10321080
const _default_bit_splice = BitVector()
10331081

10341082
function splice!(B::BitVector, r::Union{AbstractUnitRange{Int}, Integer}, ins::AbstractArray = _default_bit_splice)
1083+
r isa Bool && depwarn("passing Bool as an index is deprecated", :splice!)
10351084
_splice_int!(B, isa(r, AbstractUnitRange{Int}) ? r : Int(r), ins)
10361085
end
1086+
10371087
function _splice_int!(B::BitVector, r, ins)
10381088
n = length(B)
10391089
i_f, i_l = first(r), last(r)

test/bitarray.jl

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1711,3 +1711,40 @@ end
17111711
@test typeof([a a ;;; a a]) <: BitArray
17121712
@test typeof([a a ;;; [a a]]) <: BitArray
17131713
end
1714+
1715+
@testset "deleteat! additional tests" begin
1716+
for v in ([1, 2, 3], [true, true, true], trues(3))
1717+
@test_throws BoundsError deleteat!(v, true:true)
1718+
end
1719+
1720+
for v in ([1], [true], trues(1))
1721+
@test length(deleteat!(v, false:false)) == 1
1722+
@test isempty(deleteat!(v, true:true))
1723+
end
1724+
1725+
x = trues(3)
1726+
x[3] = false
1727+
@test deleteat!(x, [UInt8(2)]) == [true, false]
1728+
@test_throws ArgumentError deleteat!(x, Any[true])
1729+
@test_throws ArgumentError deleteat!(x, Any[1, true])
1730+
@test_throws ArgumentError deleteat!(x, Any[2, 1])
1731+
@test_throws BoundsError deleteat!(x, Any[4])
1732+
@test_throws BoundsError deleteat!(x, Any[2, 4])
1733+
1734+
function test_equivalence(n::Int)
1735+
x1 = rand(Bool, n)
1736+
x2 = BitVector(x1)
1737+
inds1 = rand(Bool, n)
1738+
inds2 = BitVector(inds1)
1739+
return deleteat!(copy(x1), findall(inds1)) ==
1740+
deleteat!(copy(x1), inds1) ==
1741+
deleteat!(copy(x2), inds1) ==
1742+
deleteat!(copy(x1), inds2) ==
1743+
deleteat!(copy(x2), inds2)
1744+
end
1745+
1746+
Random.seed!(1234)
1747+
for n in 1:20, _ in 1:100
1748+
@test test_equivalence(n)
1749+
end
1750+
end

0 commit comments

Comments
 (0)