• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JuliaLang / julia / #37858

01 Aug 2024 09:01PM UTC coverage: 87.527% (-0.07%) from 87.6%
#37858

push

local

web-flow
more small changes for trimming (#55255)

A few more unobjectionable, NFC changes from #55047.

2 of 7 new or added lines in 2 files covered. (28.57%)

624 existing lines in 20 files now uncovered.

77701 of 88774 relevant lines covered (87.53%)

15369152.56 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.72
/base/bitarray.jl
1
# This file is a part of Julia. License is MIT: https://julialang.org/license
2

3
## BitArray
4

5
# notes: bits are stored in contiguous chunks
6
#        unused bits must always be set to 0
7
"""
8
    BitArray{N} <: AbstractArray{Bool, N}
9

10
Space-efficient `N`-dimensional boolean array, using just one bit for each boolean value.
11

12
`BitArray`s pack up to 64 values into every 8 bytes, resulting in an 8x space efficiency
13
over `Array{Bool, N}` and allowing some operations to work on 64 values at once.
14

15
By default, Julia returns `BitArrays` from [broadcasting](@ref Broadcasting) operations
16
that generate boolean elements (including dotted-comparisons like `.==`) as well as from
17
the functions [`trues`](@ref) and [`falses`](@ref).
18

19
!!! note
20
    Due to its packed storage format, concurrent access to the elements of a `BitArray`
21
    where at least one of them is a write is not thread-safe.
22

23
"""
24
mutable struct BitArray{N} <: AbstractArray{Bool, N}
25
    chunks::Vector{UInt64}
26
    len::Int
27
    dims::NTuple{N,Int}
28
    function BitArray{N}(::UndefInitializer, dims::Vararg{Int,N}) where N
14,790✔
29
        n = 1
11,072✔
30
        i = 1
11,072✔
31
        for d in dims
4,980,937✔
32
            d >= 0 || throw(ArgumentError("dimension size must be ≥ 0, got $d for dimension $i"))
4,996,203✔
33
            n *= d
4,996,203✔
34
            i += 1
34,408✔
35
        end
5,010,975✔
36
        nc = num_bit_chunks(n)
4,980,937✔
37
        chunks = Vector{UInt64}(undef, nc)
9,949,696✔
38
        nc > 0 && (chunks[end] = UInt64(0))
4,980,937✔
39
        b = new(chunks, n)
4,981,226✔
40
        N != 1 && (b.dims = dims)
19,142✔
41
        return b
4,980,937✔
42
    end
43
end
44

45
# note: the docs for the two signatures are unified, but only
46
# the first one is recognized by the help system; it would be nice
47
# to fix this.
48
"""
49
    BitArray(undef, dims::Integer...)
50
    BitArray{N}(undef, dims::NTuple{N,Int})
51

52
Construct an undef [`BitArray`](@ref) with the given dimensions.
53
Behaves identically to the [`Array`](@ref) constructor. See [`undef`](@ref).
54

55
# Examples
56
```julia-repl
57
julia> BitArray(undef, 2, 2)
58
2×2 BitMatrix:
59
 0  0
60
 0  0
61

62
julia> BitArray(undef, (3, 1))
63
3×1 BitMatrix:
64
 0
65
 0
66
 0
67
```
68
"""
69
BitArray(::UndefInitializer, dims::Integer...) = BitArray(undef, map(Int,dims))
3✔
70
BitArray{N}(::UndefInitializer, dims::Integer...) where {N} = BitArray{N}(undef, map(Int,dims))::BitArray{N}
1✔
71
BitArray(::UndefInitializer, dims::NTuple{N,Integer}) where {N} = BitArray{N}(undef, map(Int, dims)...)
4,859,904✔
72
BitArray{N}(::UndefInitializer, dims::NTuple{N,Integer}) where {N} = BitArray{N}(undef, map(Int, dims)...)
1✔
73

74
const BitVector = BitArray{1}
75
const BitMatrix = BitArray{2}
76

77
BitVector() = BitVector(undef, 0)
289✔
78

79
"""
80
    BitVector(nt::Tuple{Vararg{Bool}})
81

82
Construct a `BitVector` from a tuple of `Bool`.
83
# Examples
84
```julia-repl
85
julia> nt = (true, false, true, false)
86
(true, false, true, false)
87

88
julia> BitVector(nt)
89
4-element BitVector:
90
 1
91
 0
92
 1
93
 0
94
```
95
"""
96
function BitVector(nt::Tuple{Vararg{Bool}})
4✔
97
    bv = BitVector(undef, length(nt))
4✔
98
    bv .= nt
4✔
99
end
100

101
## utility functions ##
102

103
length(B::BitArray) = B.len
77,010,089✔
104
size(B::BitVector) = (B.len,)
82,257,365✔
105
size(B::BitArray) = B.dims
4,731,853✔
106

107
@inline function size(B::BitVector, d::Integer)
2✔
108
    d < 1 && throw_boundserror(size(B), d)
92✔
109
    ifelse(d == 1, B.len, 1)
91✔
110
end
111

112
isassigned(B::BitArray, i::Int) = 1 <= i <= length(B)
2,901✔
113

114
IndexStyle(::Type{<:BitArray}) = IndexLinear()
3,757,727✔
115

116
## aux functions ##
117

118
const _msk64 = ~UInt64(0)
119
@inline _div64(l) = l >> 6
1,409,121,474✔
120
@inline _mod64(l) = l & 63
1,205,786,638✔
121
@inline _blsr(x)= x & (x-1) #zeros the last set bit. Has native instruction on many archs. needed in multidimensional.jl
245,115,868✔
122
@inline _msk_end(l::Int) = _msk64 >>> _mod64(-l)
735,646✔
123
@inline _msk_end(B::BitArray) = _msk_end(length(B))
216,508✔
124
num_bit_chunks(n::Int) = _div64(n+63)
5,450,696✔
125

126
@inline get_chunks_id(i::Int) = _div64(i-1)+1, _mod64(i-1)
188,834,158✔
127

128
function glue_src_bitchunks(src::Vector{UInt64}, k::Int, ks1::Int, msk_s0::UInt64, ls0::Int)
129
    @inbounds begin
×
130
        chunk = ((src[k] & msk_s0) >>> ls0)
1,620,640✔
131
        if ks1 > k && ls0 > 0
1,620,640✔
132
            chunk_n = (src[k + 1] & ~msk_s0)
464,792✔
133
            chunk |= (chunk_n << (64 - ls0))
464,792✔
134
        end
135
    end
136
    return chunk
1,620,640✔
137
end
138

139
function copy_chunks!(dest::Vector{UInt64}, pos_d::Int, src::Vector{UInt64}, pos_s::Int, numbits::Int)
1,182,599✔
140
    numbits == 0 && return
1,182,599✔
141
    if dest === src && pos_d > pos_s
1,141,878✔
142
        return copy_chunks_rtol!(dest, pos_d, pos_s, numbits)
30,172✔
143
    end
144

145
    kd0, ld0 = get_chunks_id(pos_d)
1,111,706✔
146
    kd1, ld1 = get_chunks_id(pos_d + numbits - 1)
1,111,706✔
147
    ks0, ls0 = get_chunks_id(pos_s)
1,111,706✔
148
    ks1, ls1 = get_chunks_id(pos_s + numbits - 1)
1,111,706✔
149

150
    delta_kd = kd1 - kd0
1,111,706✔
151
    delta_ks = ks1 - ks0
1,111,706✔
152

153
    u = _msk64
×
154
    if delta_kd == 0
1,111,706✔
155
        msk_d0 = ~(u << ld0) | (u << (ld1+1))
829,746✔
156
    else
157
        msk_d0 = ~(u << ld0)
281,960✔
158
        msk_d1 = (u << (ld1+1))
281,960✔
159
    end
160
    if delta_ks == 0
1,111,706✔
161
        msk_s0 = (u << ls0) & ~(u << (ls1+1))
813,870✔
162
    else
163
        msk_s0 = (u << ls0)
297,836✔
164
    end
165

166
    chunk_s0 = glue_src_bitchunks(src, ks0, ks1, msk_s0, ls0)
1,111,706✔
167

168
    dest[kd0] = (dest[kd0] & msk_d0) | ((chunk_s0 << ld0) & ~msk_d0)
1,111,706✔
169

170
    delta_kd == 0 && return
1,111,706✔
171

172
    for i = 1 : kd1 - kd0 - 1
281,960✔
173
        chunk_s1 = glue_src_bitchunks(src, ks0 + i, ks1, msk_s0, ls0)
264,246✔
174

175
        chunk_s = (chunk_s0 >>> (64 - ld0)) | (chunk_s1 << ld0)
264,246✔
176

177
        dest[kd0 + i] = chunk_s
264,246✔
178

179
        chunk_s0 = chunk_s1
×
180
    end
387,504✔
181

182
    if ks1 >= ks0 + delta_kd
281,960✔
183
        chunk_s1 = glue_src_bitchunks(src, ks0 + delta_kd, ks1, msk_s0, ls0)
177,143✔
184
    else
185
        chunk_s1 = UInt64(0)
×
186
    end
187

188
    chunk_s = (chunk_s0 >>> (64 - ld0)) | (chunk_s1 << ld0)
281,960✔
189

190
    dest[kd1] = (dest[kd1] & msk_d1) | (chunk_s & ~msk_d1)
281,960✔
191

192
    return
281,960✔
193
end
194

195
function copy_chunks_rtol!(chunks::Vector{UInt64}, pos_d::Int, pos_s::Int, numbits::Int)
30,172✔
196
    pos_d == pos_s && return
30,172✔
197
    pos_d < pos_s && return copy_chunks!(chunks, pos_d, chunks, pos_s, numbits)
30,172✔
198

199
    left = numbits
×
200
    s = min(left, 64)
30,172✔
201
    b = left - s
30,172✔
202
    ps = pos_s + b
30,172✔
203
    pd = pos_d + b
30,172✔
204
    u = _msk64
×
205
    while left > 0
97,717✔
206
        kd0, ld0 = get_chunks_id(pd)
67,545✔
207
        kd1, ld1 = get_chunks_id(pd + s - 1)
67,545✔
208
        ks0, ls0 = get_chunks_id(ps)
67,545✔
209
        ks1, ls1 = get_chunks_id(ps + s - 1)
67,545✔
210

211
        delta_kd = kd1 - kd0
67,545✔
212
        delta_ks = ks1 - ks0
67,545✔
213

214
        if delta_kd == 0
67,545✔
215
            msk_d0 = ~(u << ld0) | (u << (ld1+1))
16,712✔
216
        else
217
            msk_d0 = ~(u << ld0)
50,833✔
218
            msk_d1 = (u << (ld1+1))
50,833✔
219
        end
220
        if delta_ks == 0
67,545✔
221
            msk_s0 = (u << ls0) & ~(u << (ls1+1))
7,000✔
222
        else
223
            msk_s0 = (u << ls0)
60,545✔
224
        end
225

226
        chunk_s0 = glue_src_bitchunks(chunks, ks0, ks1, msk_s0, ls0) & ~(u << s)
67,545✔
227
        chunks[kd0] = (chunks[kd0] & msk_d0) | ((chunk_s0 << ld0) & ~msk_d0)
67,545✔
228

229
        if delta_kd != 0
67,545✔
230
            chunk_s = (chunk_s0 >>> (64 - ld0))
50,833✔
231

232
            chunks[kd1] = (chunks[kd1] & msk_d1) | (chunk_s & ~msk_d1)
50,833✔
233
        end
234

235
        left -= s
67,545✔
236
        s = min(left, 64)
67,545✔
237
        b = left - s
67,545✔
238
        ps = pos_s + b
67,545✔
239
        pd = pos_d + b
67,545✔
240
    end
67,545✔
241
end
242

243
function fill_chunks!(Bc::Array{UInt64}, x::Bool, pos::Int, numbits::Int)
2,086✔
244
    numbits <= 0 && return
2,086✔
245
    k0, l0 = get_chunks_id(pos)
2,086✔
246
    k1, l1 = get_chunks_id(pos+numbits-1)
2,086✔
247

248
    u = _msk64
×
249
    if k1 == k0
2,086✔
250
        msk0 = (u << l0) & ~(u << (l1+1))
1,982✔
251
    else
252
        msk0 = (u << l0)
104✔
253
        msk1 = ~(u << (l1+1))
104✔
254
    end
255
    @inbounds if x
2,086✔
256
        Bc[k0] |= msk0
1,883✔
257
        for k = k0+1:k1-1
3,733✔
258
            Bc[k] = u
156✔
259
        end
279✔
260
        k1 > k0 && (Bc[k1] |= msk1)
1,883✔
261
    else
262
        Bc[k0] &= ~msk0
203✔
263
        for k = k0+1:k1-1
376✔
264
            Bc[k] = 0
138✔
265
        end
246✔
266
        k1 > k0 && (Bc[k1] &= ~msk1)
2,289✔
267
    end
268
end
269

270
copy_to_bitarray_chunks!(dest::Vector{UInt64}, pos_d::Int, src::BitArray, pos_s::Int, numbits::Int) =
28,782✔
271
    copy_chunks!(dest, pos_d, src.chunks, pos_s, numbits)
272

273
# pack 8 Bools encoded as one contiguous UIn64 into a single byte, e.g.:
274
# 0000001:0000001:00000000:00000000:00000001:00000000:00000000:00000001 → 11001001 → 0xc9
275
function pack8bools(z::UInt64)
276
    z |= z >>> 7
66,496✔
277
    z |= z >>> 14
66,496✔
278
    z |= z >>> 28
66,496✔
279
    z &= 0xFF
66,496✔
280
    return z
66,496✔
281
end
282

283
function copy_to_bitarray_chunks!(Bc::Vector{UInt64}, pos_d::Int, C::Array{Bool}, pos_s::Int, numbits::Int)
116,247✔
284
    kd0, ld0 = get_chunks_id(pos_d)
116,247✔
285
    kd1, ld1 = get_chunks_id(pos_d + numbits - 1)
116,247✔
286

287
    delta_kd = kd1 - kd0
116,247✔
288

289
    u = _msk64
116,158✔
290
    if delta_kd == 0
116,247✔
291
        msk_d0 = msk_d1 = ~(u << ld0) | (u << (ld1+1))
17,282✔
292
        lt0 = ld1
17,194✔
293
    else
294
        msk_d0 = ~(u << ld0)
98,965✔
295
        msk_d1 = (u << (ld1+1))
98,965✔
296
        lt0 = 63
98,964✔
297
    end
298

299
    bind = kd0
116,247✔
300
    ind = pos_s
116,158✔
301
    @inbounds if ld0 > 0
116,247✔
302
        c = UInt64(0)
20,908✔
303
        for j = ld0:lt0
20,908✔
304
            c |= (UInt64(C[ind]) << j)
128,636✔
305
            ind += 1
128,636✔
306
        end
236,364✔
307
        Bc[kd0] = (Bc[kd0] & msk_d0) | (c & ~msk_d0)
20,908✔
308
        bind += 1
20,908✔
309
    end
310

311
    nc = _div64(numbits - ind + pos_s)
116,247✔
312
    nc8 = (nc >>> 3) << 3
116,247✔
313
    if nc8 > 0
116,247✔
314
        ind8 = 1
1,018✔
315
        P8 = Ptr{UInt64}(pointer(C, ind)) # unaligned i64 pointer
1,018✔
316
        @inbounds for i = 1:nc8
1,018✔
317
            c = UInt64(0)
8,312✔
318
            for j = 0:7
8,312✔
319
                # unaligned load
320
                c |= (pack8bools(unsafe_load(P8, ind8)) << (j<<3))
66,496✔
321
                ind8 += 1
66,496✔
322
            end
124,680✔
323
            Bc[bind] = c
8,312✔
324
            bind += 1
8,312✔
325
        end
15,606✔
326
        ind += (ind8-1) << 3
1,018✔
327
    end
328
    @inbounds for i = (nc8+1):nc
131,964✔
329
        c = UInt64(0)
236,913✔
330
        for j = 0:63
242,673✔
331
            c |= (UInt64(C[ind]) << j)
15,168,192✔
332
            ind += 1
15,168,192✔
333
        end
30,099,381✔
334
        Bc[bind] = c
237,003✔
335
        bind += 1
237,003✔
336
    end
373,476✔
337
    @inbounds if bind ≤ kd1
116,247✔
338
        @assert bind == kd1
13,200✔
339
        c = UInt64(0)
13,200✔
340
        for j = 0:ld1
13,200✔
341
            c |= (UInt64(C[ind]) << j)
458,453✔
342
            ind += 1
458,453✔
343
        end
903,706✔
344
        Bc[kd1] = (Bc[kd1] & msk_d1) | (c & ~msk_d1)
13,200✔
345
    end
346
end
347

348
## More definitions in multidimensional.jl
349

350
# auxiliary definitions used when filling a BitArray via a Vector{Bool} cache
351
# (e.g. when constructing from an iterable, or in broadcast!)
352

353
const bitcache_chunks = 64 # this can be changed
354
const bitcache_size = 64 * bitcache_chunks # do not change this
355

356
dumpbitcache(Bc::Vector{UInt64}, bind::Int, C::Vector{Bool}) =
92,427✔
357
    copy_to_bitarray_chunks!(Bc, ((bind - 1) << 6) + 1, C, 1, min(bitcache_size, (length(Bc)-bind+1) << 6))
358

359

360
## custom iterator ##
361
function iterate(B::BitArray, i::Int=0)
4,998✔
362
    i >= length(B) && return nothing
64,891,148✔
363
    (B.chunks[_div64(i)+1] & (UInt64(1)<<_mod64(i)) != 0, i+1)
64,388,534✔
364
end
365

366
## similar, fill!, copy! etc ##
367

368
similar(B::BitArray) = BitArray(undef, size(B))
154,225✔
369
similar(B::BitArray, dims::Int...) = BitArray(undef, dims)
2✔
370
similar(B::BitArray, dims::Dims) = BitArray(undef, dims...)
1✔
371

372
similar(B::BitArray, T::Type{Bool}, dims::Dims) = BitArray(undef, dims)
90,203✔
373
# changing type to a non-Bool returns an Array
374
# (this triggers conversions like float(bitvector) etc.)
375
similar(B::BitArray, T::Type, dims::Dims) = Array{T}(undef, dims)
24,141✔
376

377
function fill!(B::BitArray, x)
4,439,141✔
378
    y = convert(Bool, x)
50,986✔
379
    isempty(B) && return B
4,439,141✔
380
    Bc = B.chunks
4,439,016✔
381
    if !y
4,439,016✔
382
        fill!(Bc, 0)
5,445,983✔
383
    else
384
        fill!(Bc, _msk64)
14,729✔
385
        Bc[end] &= _msk_end(B)
1,909✔
386
    end
387
    return B
4,439,016✔
388
end
389

390
"""
391
    falses(dims)
392

393
Create a `BitArray` with all values set to `false`.
394

395
# Examples
396
```jldoctest
397
julia> falses(2,3)
398
2×3 BitMatrix:
399
 0  0  0
400
 0  0  0
401
```
402
"""
403
falses(dims::DimOrInd...) = falses(dims)
4,334,530✔
404
falses(dims::NTuple{N, Union{Integer, OneTo}}) where {N} = falses(map(to_dim, dims))
9✔
405
falses(dims::NTuple{N, Integer}) where {N} = fill!(BitArray(undef, dims), false)
4,335,299✔
406
falses(dims::Tuple{}) = fill!(BitArray(undef, dims), false)
10✔
UNCOV
407
falses(dims::NTuple{N, DimOrInd}) where {N} = fill!(similar(BitArray, dims), false)
×
408

409
"""
410
    trues(dims)
411

412
Create a `BitArray` with all values set to `true`.
413

414
# Examples
415
```jldoctest
416
julia> trues(2,3)
417
2×3 BitMatrix:
418
 1  1  1
419
 1  1  1
420
```
421
"""
422
trues(dims::DimOrInd...) = trues(dims)
2,073✔
423
trues(dims::NTuple{N, Union{Integer, OneTo}}) where {N} = trues(map(to_dim, dims))
×
424
trues(dims::NTuple{N, Integer}) where {N} = fill!(BitArray(undef, dims), true)
2,085✔
425
trues(dims::Tuple{}) = fill!(BitArray(undef, dims), true)
6✔
UNCOV
426
trues(dims::NTuple{N, DimOrInd}) where {N} = fill!(similar(BitArray, dims), true)
×
427

428
function one(x::BitMatrix)
2✔
429
    m, n = size(x)
2✔
430
    m == n || throw(DimensionMismatch("multiplicative identity defined only for square matrices"))
3✔
431
    a = falses(n, n)
1✔
432
    for i = 1:n
1✔
433
        a[i,i] = true
2✔
434
    end
3✔
435
    return a
1✔
436
end
437

438
function copyto!(dest::BitArray, src::BitArray)
152,225✔
439
    length(src) > length(dest) && throw(BoundsError(dest, length(dest)+1))
152,225✔
440
    destc = dest.chunks; srcc = src.chunks
152,224✔
441
    nc = min(length(destc), length(srcc))
152,224✔
442
    nc == 0 && return dest
152,224✔
443
    @inbounds begin
146,428✔
444
        for i = 1 : nc - 1
152,221✔
445
            destc[i] = srcc[i]
575,726✔
446
        end
1,008,965✔
447
        if length(src) == length(dest)
152,221✔
448
            destc[nc] = srcc[nc]
152,219✔
449
        else
450
            msk_s = _msk_end(src)
2✔
451
            msk_d = ~msk_s
2✔
452
            destc[nc] = (msk_d & destc[nc]) | (msk_s & srcc[nc])
2✔
453
        end
454
    end
455
    return dest
152,221✔
456
end
457

458
function unsafe_copyto!(dest::BitArray, doffs::Integer, src::Union{BitArray,Array}, soffs::Integer, n::Integer)
459
    copy_to_bitarray_chunks!(dest.chunks, Int(doffs), src, Int(soffs), Int(n))
62,345✔
460
    return dest
62,345✔
461
end
462

463
copyto!(dest::BitArray, doffs::Integer, src::Union{BitArray,Array}, soffs::Integer, n::Integer) =
142,348✔
464
    _copyto_int!(dest, Int(doffs), src, Int(soffs), Int(n))
465
function _copyto_int!(dest::BitArray, doffs::Int, src::Union{BitArray,Array}, soffs::Int, n::Int)
142,348✔
466
    n == 0 && return dest
142,348✔
467
    n < 0 && throw(ArgumentError("Number of elements to copy must be non-negative."))
142,218✔
468
    soffs < 1 && throw(BoundsError(src, soffs))
142,217✔
469
    doffs < 1 && throw(BoundsError(dest, doffs))
142,216✔
470
    soffs+n-1 > length(src) && throw(BoundsError(src, length(src)+1))
142,213✔
471
    doffs+n-1 > length(dest) && throw(BoundsError(dest, length(dest)+1))
83,843✔
472
    return unsafe_copyto!(dest, doffs, src, soffs, n)
62,341✔
473
end
474

475
function copyto!(dest::BitArray, src::Array)
5✔
476
    length(src) > length(dest) && throw(BoundsError(dest, length(dest)+1))
5✔
477
    length(src) == 0 && return dest
5✔
478
    return unsafe_copyto!(dest, 1, src, 1, length(src))
4✔
479
end
480

481
function reshape(B::BitArray{N}, dims::NTuple{N,Int}) where N
4✔
482
    return dims == size(B) ? B : _bitreshape(B, dims)
7✔
483
end
484
reshape(B::BitArray, dims::Tuple{Vararg{Int}}) = _bitreshape(B, dims)
220✔
485
function _bitreshape(B::BitArray, dims::NTuple{N,Int}) where N
1✔
486
    prod(dims) == length(B) ||
227✔
487
        throw(DimensionMismatch("new dimensions $(dims) must be consistent with array length $(length(B))"))
488
    Br = BitArray{N}(undef, ntuple(i->0,Val(N))...)
223✔
489
    Br.chunks = B.chunks
223✔
490
    Br.len = prod(dims)
223✔
491
    N != 1 && (Br.dims = dims)
223✔
492
    return Br
223✔
493
end
494

495
## Constructors ##
496

497
function Array{T,N}(B::BitArray{N}) where {T,N}
3,990✔
498
    A = Array{T,N}(undef, size(B))
551,889✔
499
    Bc = B.chunks
277,434✔
500
    @inbounds for i = 1:length(A)
277,434✔
501
        A[i] = unsafe_bitgetindex(Bc, i)
97,960,648✔
502
    end
195,646,821✔
503
    return A
277,434✔
504
end
505

506
BitArray(A::AbstractArray{<:Any,N}) where {N} = BitArray{N}(A)
14,687✔
507

508
function BitArray{N}(A::AbstractArray{T,N}) where N where T
20,957✔
509
    B = BitArray(undef, convert(Dims{N}, size(A)::Dims{N}))
20,976✔
510
    _checkaxs(axes(B), axes(A))
20,976✔
511
    _copyto_bitarray!(B, A)
20,974✔
512
    return B::BitArray{N}
20,972✔
513
end
514

515
function _copyto_bitarray!(B::BitArray, A::AbstractArray)
20,972✔
516
    l = length(A)
20,975✔
517
    l == 0 && return B
20,975✔
518
    l > length(B) && throw(BoundsError(B, length(B)+1))
19,406✔
519
    Bc = B.chunks
19,406✔
520
    nc = num_bit_chunks(l)
19,406✔
521
    Ai = first(eachindex(A))
11,542✔
522
    @inbounds begin
11,542✔
523
        for i = 1:nc-1
19,406✔
524
            c = UInt64(0)
14,411✔
525
            for j = 0:63
183,691✔
526
                c |= (UInt64(convert(Bool, A[Ai])::Bool) << j)
1,544,107✔
527
                Ai = nextind(A, Ai)
1,091,584✔
528
            end
2,166,112✔
529
            Bc[i] = c
17,056✔
530
        end
23,895✔
531
        c = UInt64(0)
19,406✔
532
        tail = _mod64(l - 1) + 1
19,406✔
533
        for j = 0:tail-1
19,406✔
534
            c |= (UInt64(convert(Bool, A[Ai])::Bool) << j)
839,462✔
535
            Ai = nextind(A, Ai)
620,521✔
536
        end
1,221,638✔
537
        msk = _msk_end(tail)
19,404✔
538
        Bc[nc] = (c & msk) | (Bc[nc] & ~msk)
19,404✔
539
    end
540
    return B
19,404✔
541
end
542

543
reinterpret(::Type{Bool}, B::BitArray, dims::NTuple{N,Int}) where {N} = reinterpret(B, dims)
×
544
reinterpret(B::BitArray, dims::NTuple{N,Int}) where {N} = reshape(B, dims)
×
545

546
if nameof(@__MODULE__) === :Base  # avoid method overwrite
547
(::Type{T})(x::T) where {T<:BitArray} = copy(x)::T
126✔
548
BitArray(x::BitArray) = copy(x)
73✔
549
end
550

551
"""
552
    BitArray(itr)
553

554
Construct a [`BitArray`](@ref) generated by the given iterable object.
555
The shape is inferred from the `itr` object.
556

557
# Examples
558
```jldoctest
559
julia> BitArray([1 0; 0 1])
560
2×2 BitMatrix:
561
 1  0
562
 0  1
563

564
julia> BitArray(x+y == 3 for x = 1:2, y = 1:3)
565
2×3 BitMatrix:
566
 0  1  0
567
 1  0  0
568

569
julia> BitArray(x+y == 3 for x = 1:2 for y = 1:3)
570
6-element BitVector:
571
 0
572
 1
573
 0
574
 1
575
 0
576
 0
577
```
578
"""
579
BitArray(itr) = gen_bitarray(IteratorSize(itr), itr)
10✔
580
BitArray{N}(itr) where N = gen_bitarrayN(BitArray{N}, IteratorSize(itr), itr)
93,469✔
581

582
convert(::Type{T}, a::AbstractArray) where {T<:BitArray} = a isa T ? a : T(a)::T
74,899✔
583

584
# generic constructor from an iterable without compile-time info
585
# (we pass start(itr) explicitly to avoid a type-instability with filters)
586
gen_bitarray(isz::IteratorSize, itr) = gen_bitarray_from_itr(itr)
4,178✔
587

588
# generic iterable with known shape
589
function gen_bitarray(::HasShape, itr)
590
    B = BitArray(undef, size(itr))
4✔
591
    for (I,x) in zip(CartesianIndices(axes(itr)), itr)
4✔
592
        B[I] = x
4✔
593
    end
4✔
594
    return B
4✔
595
end
596

597
# generator with known shape or length
598
function gen_bitarray(::HasShape, itr::Generator)
599
    B = BitArray(undef, size(itr))
89,293✔
600
    return fill_bitarray_from_itr!(B, itr)
89,293✔
601
end
602
function gen_bitarray(::HasLength, itr)
×
603
    b = BitVector(undef, length(itr))
×
604
    return fill_bitarray_from_itr!(b, itr)
×
605
end
606

607
gen_bitarray(::IsInfinite, itr) =  throw(ArgumentError("infinite-size iterable used in BitArray constructor"))
1✔
608

609
gen_bitarrayN(::Type{BitVector}, itsz, itr)                        = gen_bitarray(itsz, itr)
4,176✔
610
gen_bitarrayN(::Type{BitVector}, itsz::HasShape{1}, itr)           = gen_bitarray(itsz, itr)
89,290✔
611
gen_bitarrayN(::Type{BitArray{N}}, itsz::HasShape{N}, itr) where N = gen_bitarray(itsz, itr)
×
612
# The first of these is just for ambiguity resolution
613
gen_bitarrayN(::Type{BitVector}, itsz::HasShape{N}, itr) where N      = throw(DimensionMismatch("cannot create a BitVector from a $N-dimensional iterator"))
2✔
614
gen_bitarrayN(@nospecialize(T::Type), itsz::HasShape{N}, itr) where N = throw(DimensionMismatch("cannot create a $T from a $N-dimensional iterator"))
1✔
615
gen_bitarrayN(@nospecialize(T::Type), itsz, itr) = throw(DimensionMismatch("cannot create a $T from a generic iterator"))
×
616

617
# The aux functions gen_bitarray_from_itr and fill_bitarray_from_itr! both
618
# use a Vector{Bool} cache for performance reasons
619

620
function gen_bitarray_from_itr(itr)
4,178✔
621
    B = empty!(BitVector(undef, bitcache_size))
267,392✔
622
    C = Vector{Bool}(undef, bitcache_size)
4,178✔
623
    Bc = B.chunks
4,178✔
624
    ind = 1
4,178✔
625
    cind = 1
4,178✔
626
    y = iterate(itr)
7,834✔
627
    while y !== nothing
305,967✔
628
        x, st = y
301,789✔
629
        @inbounds C[ind] = x
301,789✔
630
        ind += 1
301,789✔
631
        if ind > bitcache_size
301,789✔
632
            resize!(B, length(B) + bitcache_size)
×
633
            dumpbitcache(Bc, cind, C)
×
634
            cind += bitcache_chunks
×
635
            ind = 1
×
636
        end
637
        y = iterate(itr, st)
599,583✔
638
    end
301,789✔
639
    if ind > 1
4,178✔
640
        @inbounds C[ind:bitcache_size] .= false
14,673,187✔
641
        resize!(B, length(B) + ind - 1)
3,656✔
642
        dumpbitcache(Bc, cind, C)
3,656✔
643
    end
644
    return B
4,178✔
645
end
646

647
function fill_bitarray_from_itr!(B::BitArray, itr)
89,293✔
648
    n = length(B)
89,204✔
649
    C = Vector{Bool}(undef, bitcache_size)
89,293✔
650
    Bc = B.chunks
89,293✔
651
    ind = 1
89,204✔
652
    cind = 1
89,204✔
653
    y = iterate(itr)
178,064✔
654
    while y !== nothing
8,679,011✔
655
        x, st = y
8,589,143✔
656
        @inbounds C[ind] = x
8,589,718✔
657
        ind += 1
8,589,718✔
658
        if ind > bitcache_size
8,589,718✔
659
            dumpbitcache(Bc, cind, C)
×
660
            cind += bitcache_chunks
×
661
            ind = 1
×
662
        end
663
        y = iterate(itr, st)
17,090,665✔
664
    end
8,589,718✔
665
    if ind > 1
89,293✔
666
        @inbounds C[ind:bitcache_size] .= false
355,016,298✔
667
        dumpbitcache(Bc, cind, C)
88,771✔
668
    end
669
    return B
89,293✔
670
end
671

672

673
## Indexing: getindex ##
674

675
@inline function unsafe_bitgetindex(Bc::Vector{UInt64}, i::Int)
676
    i1, i2 = get_chunks_id(i)
168,945,212✔
677
    u = UInt64(1) << i2
168,903,102✔
678
    @inbounds r = (Bc[i1] & u) != 0
168,945,212✔
679
    return r
168,945,212✔
680
end
681

682
@inline function getindex(B::BitArray, i::Int)
1,440✔
683
    @boundscheck checkbounds(B, i)
70,331,013✔
684
    unsafe_bitgetindex(B.chunks, i)
70,331,013✔
685
end
686

687
## Indexing: setindex! ##
688

689
@inline function unsafe_bitsetindex!(Bc::Array{UInt64}, x::Bool, i::Int)
690
    i1, i2 = get_chunks_id(i)
14,882,666✔
691
    _unsafe_bitsetindex!(Bc, x, i1, i2)
14,882,666✔
692
end
693

694
@inline function _unsafe_bitsetindex!(Bc::Array{UInt64}, x::Bool, i1::Int, i2::Int)
695
    u = UInt64(1) << i2
642,977,004✔
696
    @inbounds begin
30✔
697
        c = Bc[i1]
696,315,011✔
698
        Bc[i1] = ifelse(x, c | u, c & ~u)
696,315,011✔
699
    end
700
end
701

702
@inline function setindex!(B::BitArray, x, i::Int)
6,780✔
703
    @boundscheck checkbounds(B, i)
14,224,062✔
704
    unsafe_bitsetindex!(B.chunks, convert(Bool, x), i)
14,224,062✔
705
    return B
14,224,062✔
706
end
707

708
indexoffset(i) = first(i)-1
86,092✔
709
indexoffset(::Colon) = 0
×
710

711
@propagate_inbounds function setindex!(B::BitArray, X::AbstractArray, J0::Union{Colon,AbstractUnitRange{Int}})
34✔
712
    _setindex!(IndexStyle(B), B, X, to_indices(B, (J0,))[1])
34✔
713
end
714

715
# Assigning an array of bools is more complicated, but we can still do some
716
# work on chunks by combining X and I 64 bits at a time to improve perf by ~40%
717
@inline function setindex!(B::BitArray, X::AbstractArray, I::BitArray)
3✔
718
    @boundscheck checkbounds(B, I)
3✔
719
    _unsafe_setindex!(B, X, I)
3✔
720
end
721
function _unsafe_setindex!(B::BitArray, X::AbstractArray, I::BitArray)
3✔
722
    Bc = B.chunks
3✔
723
    Ic = I.chunks
3✔
724
    length(Bc) == length(Ic) || throw_boundserror(B, I)
3✔
725
    lc = length(Bc)
3✔
726
    lx = length(X)
3✔
727
    last_chunk_len = _mod64(length(B)-1)+1
3✔
728

729
    Xi = first(eachindex(X))
3✔
730
    lastXi = last(eachindex(X))
3✔
731
    for i = 1:lc
3✔
732
        @inbounds Imsk = Ic[i]
179✔
733
        @inbounds C = Bc[i]
179✔
734
        u = UInt64(1)
179✔
735
        for j = 1:(i < lc ? 64 : last_chunk_len)
179✔
736
            if Imsk & u != 0
11,340✔
737
                Xi > lastXi && throw_setindex_mismatch(X, count(I))
5,718✔
738
                @inbounds x = convert(Bool, X[Xi])
5,718✔
739
                C = ifelse(x, C | u, C & ~u)
5,718✔
740
                Xi = nextind(X, Xi)
5,718✔
741
            end
742
            u <<= 1
11,340✔
743
        end
22,501✔
744
        @inbounds Bc[i] = C
179✔
745
    end
355✔
746
    if Xi != nextind(X, lastXi)
3✔
747
        throw_setindex_mismatch(X, count(I))
×
748
    end
749
    return B
3✔
750
end
751

752
## Dequeue functionality ##
753

754
function push!(B::BitVector, item)
260✔
755
    # convert first so we don't grow the bitarray if the assignment won't work
756
    item = convert(Bool, item)
260✔
757

758
    Bc = B.chunks
260✔
759

760
    l = _mod64(length(B))
260✔
761
    if l == 0
260✔
762
        _growend!(Bc, 1)
5✔
763
        Bc[end] = UInt64(0)
5✔
764
    end
765
    B.len += 1
260✔
766
    if item
260✔
767
        B[end] = true
124✔
768
    end
769
    return B
260✔
770
end
771

772
function append!(B::BitVector, items::BitVector)
2,088✔
773
    n0 = length(B)
12,564✔
774
    n1 = length(items)
12,564✔
775
    n1 == 0 && return B
12,564✔
776
    Bc = B.chunks
10,995✔
777
    k0 = length(Bc)
10,995✔
778
    k1 = num_bit_chunks(n0 + n1)
10,995✔
779
    if k1 > k0
10,995✔
780
        _growend!(Bc, k1 - k0)
9,423✔
781
        Bc[end] = UInt64(0)
9,423✔
782
    end
783
    B.len += n1
10,995✔
784
    copy_chunks!(Bc, n0+1, items.chunks, 1, n1)
10,995✔
785
    return B
10,995✔
786
end
787

788
append!(B::BitVector, items) = append!(B, BitVector(items))
10,440✔
789
append!(A::Vector{Bool}, items::BitVector) = append!(A, Array(items))
6,264✔
790

791
function prepend!(B::BitVector, items::BitVector)
4,176✔
792
    n0 = length(B)
4,176✔
793
    n1 = length(items)
4,176✔
794
    n1 == 0 && return B
4,176✔
795
    Bc = B.chunks
3,654✔
796
    k0 = length(Bc)
3,654✔
797
    k1 = num_bit_chunks(n0 + n1)
3,654✔
798
    if k1 > k0
3,654✔
799
        _growend!(Bc, k1 - k0)
3,131✔
800
        Bc[end] = UInt64(0)
3,131✔
801
    end
802
    B.len += n1
3,654✔
803
    copy_chunks!(Bc, 1 + n1, Bc, 1, n0)
3,654✔
804
    copy_chunks!(Bc, 1, items.chunks, 1, n1)
3,654✔
805
    return B
3,654✔
806
end
807

808
prepend!(B::BitVector, items) = prepend!(B, BitArray(items))
2,088✔
809
prepend!(A::Vector{Bool}, items::BitVector) = prepend!(A, Array(items))
2,088✔
810

811
function sizehint!(B::BitVector, sz::Integer)
×
812
    sizehint!(B.chunks, num_bit_chunks(sz))
×
813
    return B
×
814
end
815

816
resize!(B::BitVector, n::Integer) = _resize_int!(B, Int(n))
3,659✔
817
function _resize_int!(B::BitVector, n::Int)
3,659✔
818
    n0 = length(B)
3,659✔
819
    n == n0 && return B
3,659✔
820
    n >= 0 || throw(BoundsError(B, n))
3,660✔
821
    if n < n0
3,658✔
822
        deleteat!(B, n+1:n0)
1✔
823
        return B
1✔
824
    end
825
    Bc = B.chunks
3,657✔
826
    k0 = length(Bc)
3,657✔
827
    k1 = num_bit_chunks(n)
3,657✔
828
    if k1 > k0
3,657✔
829
        _growend!(Bc, k1 - k0)
3,657✔
830
        Bc[end] = UInt64(0)
3,657✔
831
    end
832
    B.len = n
3,657✔
833
    return B
3,657✔
834
end
835

836
function pop!(B::BitVector)
260✔
837
    isempty(B) && throw(ArgumentError("argument must not be empty"))
260✔
838
    item = B[end]
260✔
839
    B[end] = false
260✔
840

841
    l = _mod64(length(B))
260✔
842
    l == 1 && _deleteend!(B.chunks, 1)
260✔
843
    B.len -= 1
260✔
844

845
    return item
260✔
846
end
847

848
function pushfirst!(B::BitVector, item)
260✔
849
    item = convert(Bool, item)
260✔
850

851
    Bc = B.chunks
260✔
852

853
    l = _mod64(length(B))
260✔
854
    if l == 0
260✔
855
        _growend!(Bc, 1)
5✔
856
        Bc[end] = UInt64(0)
5✔
857
    end
858
    B.len += 1
260✔
859
    if B.len == 1
260✔
860
        Bc[1] = item
1✔
861
        return B
1✔
862
    end
863
    for i = length(Bc) : -1 : 2
454✔
864
        Bc[i] = (Bc[i] << 1) | (Bc[i-1] >>> 63)
400✔
865
    end
604✔
866
    Bc[1] = UInt64(item) | (Bc[1] << 1)
259✔
867
    return B
259✔
868
end
869

870
function popfirst!(B::BitVector)
260✔
871
    isempty(B) && throw(ArgumentError("argument must not be empty"))
260✔
872
    @inbounds begin
260✔
873
        item = B[1]
260✔
874

875
        Bc = B.chunks
260✔
876

877
        for i = 1 : length(Bc) - 1
260✔
878
            Bc[i] = (Bc[i] >>> 1) | (Bc[i+1] << 63)
400✔
879
        end
604✔
880

881
        l = _mod64(length(B))
260✔
882
        if l == 1
260✔
883
            _deleteend!(Bc, 1)
5✔
884
        else
885
            Bc[end] >>>= 1
255✔
886
        end
887
        B.len -= 1
260✔
888
    end
889

890
    return item
260✔
891
end
892

893
insert!(B::BitVector, i::Integer, item) = _insert_int!(B, Int(i), item)
271✔
894
function _insert_int!(B::BitVector, i::Int, item)
271✔
895
    i = Int(i)
271✔
896
    n = length(B)
271✔
897
    1 <= i <= n+1 || throw(BoundsError(B, i))
273✔
898
    item = convert(Bool, item)
275✔
899

900
    Bc = B.chunks
269✔
901

902
    k, j = get_chunks_id(i)
269✔
903

904
    l = _mod64(length(B))
269✔
905
    if l == 0
269✔
906
        _growend!(Bc, 1)
5✔
907
        Bc[end] = UInt64(0)
5✔
908
    end
909
    B.len += 1
269✔
910

911
    for t = length(Bc) : -1 : k + 1
445✔
912
        Bc[t] = (Bc[t] << 1) | (Bc[t - 1] >>> 63)
261✔
913
    end
360✔
914

915
    msk_aft = (_msk64 << j)
269✔
916
    msk_bef = ~msk_aft
269✔
917
    Bc[k] = (msk_bef & Bc[k]) | ((msk_aft & Bc[k]) << 1)
269✔
918
    B[i] = item
269✔
919
    B
269✔
920
end
921

922
function _deleteat!(B::BitVector, i::Int)
538✔
923
    k, j = get_chunks_id(i)
538✔
924

925
    msk_bef = _msk64 >>> (63 - j)
538✔
926
    msk_aft = ~msk_bef
538✔
927
    msk_bef >>>= 1
538✔
928

929
    Bc = B.chunks
538✔
930

931
    @inbounds begin
538✔
932
        Bc[k] = (msk_bef & Bc[k]) | ((msk_aft & Bc[k]) >> 1)
538✔
933
        if length(Bc) > k
538✔
934
            Bc[k] |= (Bc[k + 1] << 63)
321✔
935
        end
936

937
        for t = k + 1 : length(Bc) - 1
943✔
938
            Bc[t] = (Bc[t] >>> 1) | (Bc[t + 1] << 63)
183✔
939
        end
233✔
940

941
        l = _mod64(length(B))
538✔
942

943
        if l == 1
538✔
944
            _deleteend!(Bc, 1)
12✔
945
        elseif length(Bc) > k
526✔
946
            Bc[end] >>>= 1
311✔
947
        end
948
    end
949

950
    B.len -= 1
538✔
951

952
    return B
538✔
953
end
954

955
function deleteat!(B::BitVector, i::Integer)
270✔
956
    i isa Bool && depwarn("passing Bool as an index is deprecated", :deleteat!)
270✔
957
    i = Int(i)
270✔
958
    n = length(B)
270✔
959
    1 <= i <= n || throw(BoundsError(B, i))
271✔
960

961
    return _deleteat!(B, i)
269✔
962
end
963

964
function deleteat!(B::BitVector, r::AbstractUnitRange{Int})
33,935✔
965
    n = length(B)
33,935✔
966
    i_f = first(r)
33,935✔
967
    i_l = last(r)
33,935✔
968
    1 <= i_f || throw(BoundsError(B, i_f))
33,935✔
969
    i_l <= n || throw(BoundsError(B, n+1))
33,935✔
970

971
    Bc = B.chunks
33,935✔
972
    new_l = length(B) - length(r)
33,935✔
973
    delta_k = num_bit_chunks(new_l) - length(Bc)
33,935✔
974

975
    copy_chunks!(Bc, i_f, Bc, i_l+1, n-i_l)
33,935✔
976

977
    delta_k < 0 && _deleteend!(Bc, -delta_k)
63,188✔
978

979
    B.len = new_l
33,935✔
980

981
    if new_l > 0
33,935✔
982
        Bc[end] &= _msk_end(new_l)
33,934✔
983
    end
984

985
    return B
33,935✔
986
end
987

988
function deleteat!(B::BitVector, inds)
33,683✔
989
    n = new_l = length(B)
33,683✔
990
    y = iterate(inds)
33,683✔
991
    y === nothing && return B
33,683✔
992

993
    Bc = B.chunks
33,547✔
994

995
    (p, s) = y
33,547✔
996
    checkbounds(B, p)
33,552✔
997
    p isa Bool && throw(ArgumentError("invalid index $p of type Bool"))
33,542✔
998
    q = p+1
33,541✔
999
    new_l -= 1
33,541✔
1000
    y = iterate(inds, s)
33,541✔
1001
    while y !== nothing
1,481,822✔
1002
        (i, s) = y
1,448,286✔
1003
        if !(q <= i <= n)
1,448,286✔
1004
            i isa Bool && throw(ArgumentError("invalid index $i of type Bool"))
5✔
1005
            i < q && throw(ArgumentError("indices must be unique and sorted"))
4✔
1006
            throw(BoundsError(B, i))
2✔
1007
        end
1008
        new_l -= 1
1,448,281✔
1009
        if i > q
1,448,281✔
1010
            copy_chunks!(Bc, Int(p), Bc, Int(q), Int(i-q))
714,986✔
1011
            p += i-q
714,986✔
1012
        end
1013
        q = i+1
1,448,281✔
1014
        y = iterate(inds, s)
1,448,281✔
1015
    end
1,448,281✔
1016

1017
    q <= n && copy_chunks!(Bc, Int(p), Bc, Int(q), Int(n-q+1))
33,537✔
1018

1019
    delta_k = num_bit_chunks(new_l) - length(Bc)
33,536✔
1020
    delta_k < 0 && _deleteend!(Bc, -delta_k)
41,502✔
1021

1022
    B.len = new_l
33,536✔
1023

1024
    if new_l > 0
33,536✔
1025
        Bc[end] &= _msk_end(new_l)
33,536✔
1026
    end
1027

1028
    return B
33,536✔
1029
end
1030

1031
function deleteat!(B::BitVector, inds::AbstractVector{Bool})
4,004✔
1032
    length(inds) == length(B) || throw(BoundsError(B, inds))
4,005✔
1033

1034
    n = new_l = length(B)
4,003✔
1035
    y = findfirst(inds)
9,740✔
1036
    y === nothing && return B
4,003✔
1037

1038
    Bc = B.chunks
3,809✔
1039

1040
    p = y
3,809✔
1041
    s = y + 1
3,809✔
1042
    checkbounds(B, p)
3,809✔
1043
    q = p + 1
3,809✔
1044
    new_l -= 1
3,809✔
1045
    y = findnext(inds, s)
9,004✔
1046
    while y !== nothing
21,127✔
1047
        i = y
17,318✔
1048
        s = y + 1
17,318✔
1049
        new_l -= 1
17,318✔
1050
        if i > q
17,318✔
1051
            copy_chunks!(Bc, Int(p), Bc, Int(q), Int(i-q))
7,726✔
1052
            p += i - q
7,726✔
1053
        end
1054
        q = i + 1
17,318✔
1055
        y = findnext(inds, s)
38,949✔
1056
    end
17,318✔
1057

1058
    q <= n && copy_chunks!(Bc, Int(p), Bc, Int(q), Int(n - q + 1))
3,809✔
1059

1060
    delta_k = num_bit_chunks(new_l) - length(Bc)
3,809✔
1061
    delta_k < 0 && _deleteend!(Bc, -delta_k)
3,809✔
1062

1063
    B.len = new_l
3,809✔
1064

1065
    if new_l > 0
3,809✔
1066
        Bc[end] &= _msk_end(new_l)
3,596✔
1067
    end
1068

1069
    return B
3,809✔
1070
end
1071

1072
keepat!(B::BitVector, inds) = _keepat!(B, inds)
2✔
1073
keepat!(B::BitVector, inds::AbstractVector{Bool}) = _keepat!(B, inds)
1✔
1074

1075
function splice!(B::BitVector, i::Integer)
269✔
1076
    # TODO: after deprecation remove the four lines below
1077
    #       as v = B[i] is enough to do both bounds checking
1078
    #       and Bool check then just pass Int(i) to _deleteat!
1079
    i isa Bool && depwarn("passing Bool as an index is deprecated", :splice!)
269✔
1080
    i = Int(i)
269✔
1081
    n = length(B)
269✔
1082
    1 <= i <= n || throw(BoundsError(B, i))
269✔
1083

1084
    v = B[i]   # TODO: change to a copy if/when subscripting becomes an ArrayView
269✔
1085
    _deleteat!(B, i)
269✔
1086
    return v
269✔
1087
end
1088

1089
const _default_bit_splice = BitVector()
1090

1091
function splice!(B::BitVector, r::Union{AbstractUnitRange{Int}, Integer}, ins::AbstractArray = _default_bit_splice)
62,154✔
1092
    r isa Bool && depwarn("passing Bool as an index is deprecated", :splice!)
108,636✔
1093
    _splice_int!(B, isa(r, AbstractUnitRange{Int}) ? r : Int(r), ins)
74,706✔
1094
end
1095

1096
function _splice_int!(B::BitVector, r, ins)
74,706✔
1097
    n = length(B)
74,706✔
1098
    i_f, i_l = first(r), last(r)
74,706✔
1099
    1 <= i_f <= n+1 || throw(BoundsError(B, i_f))
74,706✔
1100
    i_l <= n || throw(BoundsError(B, n+1))
74,706✔
1101

1102
    Bins = convert(BitArray, ins)
74,706✔
1103

1104
    if (i_f > n)
74,706✔
1105
        append!(B, Bins)
69✔
1106
        return BitVector()
36✔
1107
    end
1108

1109
    v = B[r]  # TODO: change to a copy if/when subscripting becomes an ArrayView
74,670✔
1110

1111
    Bc = B.chunks
74,670✔
1112

1113
    lins = length(Bins)
74,670✔
1114
    ldel = length(r)
74,670✔
1115

1116
    new_l = length(B) + lins - ldel
74,670✔
1117
    delta_k = num_bit_chunks(new_l) - length(Bc)
74,670✔
1118

1119
    delta_k > 0 && _growend!(Bc, delta_k)
74,670✔
1120

1121
    copy_chunks!(Bc, i_f+lins, Bc, i_l+1, n-i_l)
74,670✔
1122
    copy_chunks!(Bc, i_f, Bins.chunks, 1, lins)
74,670✔
1123

1124
    delta_k < 0 && _deleteend!(Bc, -delta_k)
113,573✔
1125

1126
    B.len = new_l
74,670✔
1127

1128
    if new_l > 0
74,670✔
1129
        Bc[end] &= _msk_end(new_l)
74,666✔
1130
    end
1131

1132
    return v
74,670✔
1133
end
1134

1135
function splice!(B::BitVector, r::Union{AbstractUnitRange{Int}, Integer}, ins)
12,552✔
1136
    Bins = BitVector(undef, length(ins))
12,552✔
1137
    i = 1
12,552✔
1138
    for x in ins
25,104✔
1139
        Bins[i] = Bool(x)
1,343,416✔
1140
        i += 1
1,343,416✔
1141
    end
2,686,832✔
1142
    return splice!(B, r, Bins)
12,552✔
1143
end
1144

1145

1146
function empty!(B::BitVector)
1✔
1147
    _deleteend!(B.chunks, length(B.chunks))
267,397✔
1148
    B.len = 0
4,179✔
1149
    return B
4,179✔
1150
end
1151

1152
## Unary operators ##
1153

1154
function (-)(B::BitArray)
2✔
1155
    A = zeros(Int, size(B))
341✔
1156
    l = length(B)
2✔
1157
    l == 0 && return A
2✔
1158
    Bc = B.chunks
1✔
1159
    ind = 1
1✔
1160
    for i = 1:length(Bc)-1
1✔
1161
        u = UInt64(1)
5✔
1162
        c = Bc[i]
5✔
1163
        for j = 1:64
5✔
1164
            if c & u != 0
320✔
1165
                A[ind] = -1
146✔
1166
            end
1167
            ind += 1
320✔
1168
            u <<= 1
320✔
1169
        end
635✔
1170
    end
9✔
1171
    u = UInt64(1)
1✔
1172
    c = Bc[end]
1✔
1173
    for j = 0:_mod64(l-1)
1✔
1174
        if c & u != 0
20✔
1175
            A[ind] = -1
13✔
1176
        end
1177
        ind += 1
20✔
1178
        u <<= 1
20✔
1179
    end
39✔
1180
    return A
1✔
1181
end
1182

1183
## Binary arithmetic operators ##
1184

1185
for f in (:+, :-)
1186
    @eval function ($f)(A::BitArray, B::BitArray)
68✔
1187
        r = Array{Int}(undef, promote_shape(size(A), size(B)))
136✔
1188
        ay, by = iterate(A), iterate(B)
136✔
1189
        ri = 1
68✔
1190
        # promote_shape guarantees that A and B have the
1191
        # same iteration space
1192
        while ay !== nothing
2,606✔
1193
            @inbounds r[ri] = ($f)(ay[1], by[1])
2,538✔
1194
            ri += 1
2,538✔
1195
            ay, by = iterate(A, ay[2]), iterate(B, by[2])
5,008✔
1196
        end
2,538✔
1197
        return r
68✔
1198
    end
1199
end
1200

1201
for f in (:/, :\)
1202
    @eval begin
1203
        ($f)(A::Union{BitMatrix,BitVector}, B::Union{BitMatrix,BitVector}) = ($f)(Array(A), Array(B))
2✔
1204
    end
1205
end
1206
(/)(B::BitArray, x::Number) = (/)(Array(B), x)
1✔
1207
(/)(x::Number, B::BitArray) = (/)(x, Array(B))
×
1208

1209
## promotion to complex ##
1210

1211
# TODO?
1212

1213
## comparison operators ##
1214

1215
function (==)(A::BitArray, B::BitArray)
3,978✔
1216
    size(A) != size(B) && return false
44,912✔
1217
    return A.chunks == B.chunks
22,457✔
1218
end
1219

1220

1221
## Data movement ##
1222

1223
# TODO some of this could be optimized
1224

1225
_reverse(A::BitArray, d::Tuple{Integer}) = _reverse(A, d[1])
×
1226
function _reverse(A::BitArray, d::Int)
5✔
1227
    nd = ndims(A)
5✔
1228
    1 ≤ d ≤ nd || throw(ArgumentError("dimension $d is not 1 ≤ $d ≤ $nd"))
6✔
1229
    sd = size(A, d)
4✔
1230
    sd == 1 && return copy(A)
4✔
1231

1232
    B = similar(A)
4✔
1233

1234
    nnd = 0
4✔
1235
    for i = 1:nd
4✔
1236
        nnd += size(A,i)==1 || i==d
32✔
1237
    end
28✔
1238
    if nnd == nd
4✔
1239
        # reverse along the only non-singleton dimension
1240
        for i = 1:sd
×
1241
            B[i] = A[sd+1-i]
×
1242
        end
×
1243
        return B
×
1244
    end
1245

1246
    d_in = size(A)
4✔
1247
    leading = d_in[1:(d-1)]
7✔
1248
    M = prod(leading)
7✔
1249
    N = length(A)
4✔
1250
    stride = M * sd
4✔
1251

1252
    if M == 1
4✔
1253
        for j = 0:stride:(N-stride)
2✔
1254
            for i = 1:sd
168✔
1255
                ri = sd+1-i
840✔
1256
                B[j + ri] = A[j + i]
840✔
1257
            end
1,512✔
1258
        end
335✔
1259
    else
1260
        for i = 1:sd
3✔
1261
            ri = sd+1-i
18✔
1262
            for j=0:stride:(N-stride)
29✔
1263
                offs = j + 1 + (i-1)*M
196✔
1264
                boffs = j + 1 + (ri-1)*M
196✔
1265
                copy_chunks!(B.chunks, boffs, A.chunks, offs, M)
196✔
1266
            end
374✔
1267
        end
18✔
1268
    end
1269
    return B
4✔
1270
end
1271

1272
function _reverse!(B::BitVector, ::Colon)
×
1273
    # Basic idea: each chunk is divided into two blocks of size k = n % 64, and
1274
    # h = 64 - k. Walk from either end (with indices i and j) reversing chunks
1275
    # and separately ORing their two blocks into place.
1276
    #
1277
    #           chunk 3                  chunk 2                  chunk 1
1278
    # ┌───────────────┬───────┐┌───────────────┬───────┐┌───────────────┬───────┐
1279
    # │000000000000000│   E   ││       D       │   C   ││       B       │   A   │
1280
    # └───────────────┴───────┘└───────────────┴───────┘└───────────────┴───────┘
1281
    #                     k            h           k            h            k
1282
    # yielding;
1283
    # ┌───────────────┬───────┐┌───────────────┬───────┐┌───────────────┬───────┐
1284
    # │000000000000000│  A'   ││      B'       │  C'   ││      D'       │  E'   │
1285
    # └───────────────┴───────┘└───────────────┴───────┘└───────────────┴───────┘
1286

1287
    n = length(B)
×
1288
    n == 0 && return B
×
1289

1290
    k = _mod64(n+63) + 1
×
1291
    h = 64 - k
×
1292

1293
    i, j = 0, length(B.chunks)
×
1294
    u = UInt64(0)
×
1295
    v = bitreverse(B.chunks[j])
×
1296
    B.chunks[j] = 0
×
1297
    @inbounds while true
×
1298
        i += 1
×
1299
        if i == j
×
1300
            break
×
1301
        end
1302
        u = bitreverse(B.chunks[i])
×
1303
        B.chunks[i] = 0
×
1304
        B.chunks[j] |= u >>> h
×
1305
        B.chunks[i] |= v >>> h
×
1306

1307
        j -= 1
×
1308
        if i == j
×
1309
            break
×
1310
        end
1311
        v = bitreverse(B.chunks[j])
×
1312
        B.chunks[j] = 0
×
1313
        B.chunks[i] |= v << k
×
1314
        B.chunks[j] |= u << k
×
1315
    end
×
1316

1317
    if isodd(length(B.chunks))
×
1318
        B.chunks[i] |= v >>> h
×
1319
    else
1320
        B.chunks[i] |= u << k
×
1321
    end
1322

1323
    return B
×
1324
end
1325

1326
function (<<)(B::BitVector, i::UInt)
33,440✔
1327
    n = length(B)
33,440✔
1328
    i == 0 && return copy(B)
33,440✔
1329
    A = falses(n)
33,437✔
1330
    i < n && copy_chunks!(A.chunks, 1, B.chunks, Int(i+1), Int(n-i))
33,437✔
1331
    return A
33,437✔
1332
end
1333

1334
function (>>>)(B::BitVector, i::UInt)
67,370✔
1335
    n = length(B)
67,370✔
1336
    i == 0 && return copy(B)
67,370✔
1337
    A = falses(n)
67,365✔
1338
    i < n && copy_chunks!(A.chunks, Int(i+1), B.chunks, 1, Int(n-i))
67,365✔
1339
    return A
67,365✔
1340
end
1341

1342
"""
1343
    >>(B::BitVector, n) -> BitVector
1344

1345
Right bit shift operator, `B >> n`. For `n >= 0`, the result is `B`
1346
with elements shifted `n` positions forward, filling with `false`
1347
values. If `n < 0`, elements are shifted backwards. Equivalent to
1348
`B << -n`.
1349

1350
# Examples
1351
```jldoctest
1352
julia> B = BitVector([true, false, true, false, false])
1353
5-element BitVector:
1354
 1
1355
 0
1356
 1
1357
 0
1358
 0
1359

1360
julia> B >> 1
1361
5-element BitVector:
1362
 0
1363
 1
1364
 0
1365
 1
1366
 0
1367

1368
julia> B >> -1
1369
5-element BitVector:
1370
 0
1371
 1
1372
 0
1373
 0
1374
 0
1375
```
1376
"""
1377
(>>)(B::BitVector, i::Union{Int, UInt}) = B >>> i
134,720✔
1378

1379
# signed integer version of shift operators with handling of negative values
1380
"""
1381
    <<(B::BitVector, n) -> BitVector
1382

1383
Left bit shift operator, `B << n`. For `n >= 0`, the result is `B`
1384
with elements shifted `n` positions backwards, filling with `false`
1385
values. If `n < 0`, elements are shifted forwards. Equivalent to
1386
`B >> -n`.
1387

1388
# Examples
1389
```jldoctest
1390
julia> B = BitVector([true, false, true, false, false])
1391
5-element BitVector:
1392
 1
1393
 0
1394
 1
1395
 0
1396
 0
1397

1398
julia> B << 1
1399
5-element BitVector:
1400
 0
1401
 1
1402
 0
1403
 0
1404
 0
1405

1406
julia> B << -1
1407
5-element BitVector:
1408
 0
1409
 1
1410
 0
1411
 1
1412
 0
1413
```
1414
"""
1415
(<<)(B::BitVector, i::Int) = (i >=0 ? B << unsigned(i) : B >> unsigned(-i))
33,440✔
1416

1417
"""
1418
    >>>(B::BitVector, n) -> BitVector
1419

1420
Unsigned right bitshift operator, `B >>> n`. Equivalent to `B >> n`. See [`>>`](@ref) for
1421
details and examples.
1422
"""
1423
(>>>)(B::BitVector, i::Int) = (i >=0 ? B >> unsigned(i) : B << unsigned(-i))
67,370✔
1424

1425
circshift!(dest::BitVector, src::BitVector, i::Integer) = _circshift_int!(dest, src, Int(i))
32✔
1426
function _circshift_int!(dest::BitVector, src::BitVector, i::Int)
32✔
1427
    i = Int(i)
32✔
1428
    length(dest) == length(src) || throw(ArgumentError("destination and source should be of same size"))
32✔
1429
    n = length(dest)
32✔
1430
    i %= n
32✔
1431
    i == 0 && return (src === dest ? src : copyto!(dest, src))
32✔
1432
    Bc = (src === dest ? copy(src.chunks) : src.chunks)
48✔
1433
    if i > 0 # right
32✔
1434
        copy_chunks!(dest.chunks, i+1, Bc, 1, n-i)
16✔
1435
        copy_chunks!(dest.chunks, 1, Bc, n-i+1, i)
16✔
1436
    else # left
1437
        i = -i
16✔
1438
        copy_chunks!(dest.chunks, 1, Bc, i+1, n-i)
16✔
1439
        copy_chunks!(dest.chunks, n-i+1, Bc, 1, i)
16✔
1440
    end
1441
    return dest
32✔
1442
end
1443

1444
circshift!(B::BitVector, i::Integer) = circshift!(B, B, i)
16✔
1445

1446
## count & find ##
1447

1448
function bitcount(Bc::Vector{UInt64}; init::T=0) where {T}
60,401,187✔
1449
    n::T = init
50,702✔
1450
    @inbounds for i = 1:length(Bc)
51,684,219✔
1451
        n = (n + count_ones(Bc[i])) % T
43,439,699✔
1452
    end
52,158,287✔
1453
    return n
51,684,219✔
1454
end
1455

1456
_count(::typeof(identity), B::BitArray, ::Colon, init) = bitcount(B.chunks; init)
155,136✔
1457

1458
function unsafe_bitfindnext(Bc::Vector{UInt64}, start::Int)
1459
    chunk_start = _div64(start-1)+1
2,875,803✔
1460
    within_chunk_start = _mod64(start-1)
2,875,803✔
1461
    mask = _msk64 << within_chunk_start
2,875,803✔
1462

1463
    @inbounds begin
161,287✔
1464
        if Bc[chunk_start] & mask != 0
22,552,632✔
1465
            return (chunk_start-1) << 6 + trailing_zeros(Bc[chunk_start] & mask) + 1
14,340,253✔
1466
        end
1467

1468
        for i = chunk_start+1:length(Bc)
8,223,618✔
1469
            if Bc[i] != 0
8,334,022✔
1470
                return (i-1) << 6 + trailing_zeros(Bc[i]) + 1
1,284,345✔
1471
            end
1472
        end
14,061,095✔
1473
    end
1474
    return nothing
6,928,034✔
1475
end
1476

1477
# returns the index of the next true element, or nothing if all false
1478
function findnext(B::BitArray, start::Integer)
41,739✔
1479
    start = Int(start)
60,940✔
1480
    start > 0 || throw(BoundsError(B, start))
60,938✔
1481
    start > length(B) && return nothing
60,972✔
1482
    unsafe_bitfindnext(B.chunks, start)
59,959✔
1483
end
1484

1485
#findfirst(B::BitArray) = findnext(B, 1)  ## defined in array.jl
1486

1487
# aux function: same as findnext(~B, start), but performed without temporaries
1488
function findnextnot(B::BitArray, start::Int)
55,903✔
1489
    start > 0 || throw(BoundsError(B, start))
55,905✔
1490
    start > length(B) && return nothing
55,901✔
1491

1492
    Bc = B.chunks
55,893✔
1493
    l = length(Bc)
55,893✔
1494
    l == 0 && return nothing
55,893✔
1495

1496
    chunk_start = _div64(start-1)+1
55,893✔
1497
    within_chunk_start = _mod64(start-1)
55,893✔
1498
    mask = ~(_msk64 << within_chunk_start)
55,893✔
1499

1500
    @inbounds if chunk_start < l
55,893✔
1501
        if Bc[chunk_start] | mask != _msk64
55,467✔
1502
            return (chunk_start-1) << 6 + trailing_ones(Bc[chunk_start] | mask) + 1
25,275✔
1503
        end
1504
        for i = chunk_start+1:l-1
30,705✔
1505
            if Bc[i] != _msk64
46,997✔
1506
                return (i-1) << 6 + trailing_ones(Bc[i]) + 1
28,645✔
1507
            end
1508
        end
35,670✔
1509
        if Bc[l] != _msk_end(B)
1,547✔
1510
            return (l-1) << 6 + trailing_ones(Bc[l]) + 1
1,153✔
1511
        end
1512
    elseif Bc[l] | mask != _msk_end(B)
426✔
1513
        return (l-1) << 6 + trailing_ones(Bc[l] | mask) + 1
291✔
1514
    end
1515
    return nothing
529✔
1516
end
1517
findfirstnot(B::BitArray) = findnextnot(B,1)
261✔
1518

1519
# returns the index of the first matching element
1520
function findnext(pred::Fix2{<:Union{typeof(isequal),typeof(==)},Bool},
8✔
1521
                  B::BitArray, start::Integer)
1522
    v = pred.x
8✔
1523
    v == false && return findnextnot(B, Int(start))
8✔
1524
    v == true && return findnext(B, start)
4✔
1525
    return nothing
×
1526
end
1527
#findfirst(B::BitArray, v) = findnext(B, 1, v)  ## defined in array.jl
1528

1529
# returns the index of the first element for which the function returns true
1530
findnext(testf::Function, B::BitArray, start::Integer) = _findnext_int(testf, B, Int(start))
13,826✔
1531
function _findnext_int(testf::Function, B::BitArray, start::Int)
13,819✔
1532
    f0::Bool = testf(false)
13,827✔
1533
    f1::Bool = testf(true)
13,827✔
1534
    !f0 && f1 && return findnext(B, start)
13,827✔
1535
    f0 && !f1 && return findnextnot(B, start)
12,259✔
1536

1537
    start > 0 || throw(BoundsError(B, start))
2,364✔
1538
    start > length(B) && return nothing
2,356✔
1539
    f0 && f1 && return start
2,342✔
1540
    return nothing # last case: !f0 && !f1
1,561✔
1541
end
1542
#findfirst(testf::Function, B::BitArray) = findnext(testf, B, 1)  ## defined in array.jl
1543

1544
function unsafe_bitfindprev(Bc::Vector{UInt64}, start::Int)
41,428✔
1545
    chunk_start = _div64(start-1)+1
41,428✔
1546
    mask = _msk_end(start)
41,428✔
1547

1548
    @inbounds begin
39,453✔
1549
        if Bc[chunk_start] & mask != 0
41,428✔
1550
            return (chunk_start-1) << 6 + (top_set_bit(Bc[chunk_start] & mask))
39,060✔
1551
        end
1552

1553
        for i = (chunk_start-1):-1:1
4,654✔
1554
            if Bc[i] != 0
2,437✔
1555
                return (i-1) << 6 + (top_set_bit(Bc[i]))
2,356✔
1556
            end
1557
        end
157✔
1558
    end
1559
    return nothing
12✔
1560
end
1561

1562
# returns the index of the previous true element, or nothing if all false
1563
function findprev(B::BitArray, start::Integer)
8,588✔
1564
    start = Int(start)
13,166✔
1565
    start > 0 || return nothing
13,408✔
1566
    start > length(B) && throw(BoundsError(B, start))
13,406✔
1567
    unsafe_bitfindprev(B.chunks, start)
13,404✔
1568
end
1569

1570
function findprevnot(B::BitArray, start::Int)
21,227✔
1571
    start = Int(start)
21,227✔
1572
    start > 0 || return nothing
21,229✔
1573
    start > length(B) && throw(BoundsError(B, start))
21,225✔
1574

1575
    Bc = B.chunks
21,223✔
1576

1577
    chunk_start = _div64(start-1)+1
21,223✔
1578
    mask = ~_msk_end(start)
21,223✔
1579

1580
    @inbounds begin
21,223✔
1581
        if Bc[chunk_start] | mask != _msk64
21,223✔
1582
            return (chunk_start-1) << 6 + (64 - leading_ones(Bc[chunk_start] | mask))
17,008✔
1583
        end
1584

1585
        for i = chunk_start-1:-1:1
8,420✔
1586
            if Bc[i] != _msk64
4,235✔
1587
                return (i-1) << 6 + (64 - leading_ones(Bc[i]))
4,202✔
1588
            end
1589
        end
60✔
1590
    end
1591
    return nothing
13✔
1592
end
1593
findlastnot(B::BitArray) = findprevnot(B, length(B))
1✔
1594

1595
# returns the index of the previous matching element
1596
function findprev(pred::Fix2{<:Union{typeof(isequal),typeof(==)},Bool},
268✔
1597
                  B::BitArray, start::Integer)
1598
    v = pred.x
268✔
1599
    v == false && return findprevnot(B, Int(start))
268✔
1600
    v == true && return findprev(B, start)
264✔
1601
    return nothing
×
1602
end
1603
#findlast(B::BitArray, v) = findprev(B, 1, v)  ## defined in array.jl
1604

1605
# returns the index of the previous element for which the function returns true
1606
findprev(testf::Function, B::BitArray, start::Integer) = _findprev_int(testf, B, Int(start))
8,866✔
1607
function _findprev_int(testf::Function, B::BitArray, start::Int)
8,846✔
1608
    f0::Bool = testf(false)
8,866✔
1609
    f1::Bool = testf(true)
8,866✔
1610
    !f0 && f1 && return findprev(B, start)
8,866✔
1611
    f0 && !f1 && return findprevnot(B, start)
8,604✔
1612

1613
    start > 0 || return nothing
11✔
1614
    start > length(B) && throw(BoundsError(B, start))
6✔
1615
    f0 && f1 && return start
2✔
1616
    return nothing # last case: !f0 && !f1
1✔
1617
end
1618
#findlast(testf::Function, B::BitArray) = findprev(testf, B, 1)  ## defined in array.jl
1619

1620
function findmax(a::BitArray)
7✔
1621
    isempty(a) && throw(ArgumentError("BitArray must be non-empty"))
8✔
1622
    m, mi = false, 1
7✔
1623
    ti = 1
7✔
1624
    ac = a.chunks
7✔
1625
    for i = 1:length(ac)
7✔
1626
        @inbounds k = trailing_zeros(ac[i])
11✔
1627
        ti += k
11✔
1628
        k == 64 || return (true, @inbounds keys(a)[ti])
17✔
1629
    end
9✔
1630
    return m, @inbounds keys(a)[mi]
1✔
1631
end
1632

1633
function findmin(a::BitArray)
7✔
1634
    isempty(a) && throw(ArgumentError("BitArray must be non-empty"))
8✔
1635
    m, mi = true, 1
7✔
1636
    ti = 1
7✔
1637
    ac = a.chunks
7✔
1638
    for i = 1:length(ac)-1
7✔
1639
        @inbounds k = trailing_ones(ac[i])
6✔
1640
        ti += k
6✔
1641
        k == 64 || return (false, @inbounds keys(a)[ti])
8✔
1642
    end
7✔
1643
    l = Base._mod64(length(a)-1) + 1
5✔
1644
    @inbounds k = trailing_ones(ac[end] & Base._msk_end(l))
5✔
1645
    ti += k
5✔
1646
    k == l || return (false, @inbounds keys(a)[ti])
9✔
1647
    return (m, @inbounds keys(a)[mi])
1✔
1648
end
1649

1650
# findall helper functions
1651
# Generic case (>2 dimensions)
1652
function allindices!(I, B::BitArray)
1653
    ind = first(keys(B))
7✔
1654
    for k = 1:length(B)
7✔
1655
        I[k] = ind
505✔
1656
        ind = nextind(B, ind)
757✔
1657
    end
1,003✔
1658
end
1659

1660
# Optimized case for vector
1661
function allindices!(I, B::BitVector)
1,204✔
1662
    I[:] .= 1:length(B)
1,204✔
1663
end
1664

1665
# Optimized case for matrix
1666
function allindices!(I, B::BitMatrix)
1667
    k = 1
1✔
1668
    for c = 1:size(B,2), r = 1:size(B,1)
1✔
1669
        I[k] = CartesianIndex(r, c)
4✔
1670
        k += 1
4✔
1671
    end
5✔
1672
end
1673

1674
@inline _overflowind(i1, irest::Tuple{}, size) = (i1, irest)
5,669✔
1675
@inline function _overflowind(i1, irest, size)
1676
    i2 = irest[1]
3,540✔
1677
    while i1 > size[1]
5,638✔
1678
        i1 -= size[1]
2,098✔
1679
        i2 += 1
2,098✔
1680
    end
2,098✔
1681
    i2, irest = _overflowind(i2, tail(irest), tail(size))
3,540✔
1682
    return (i1, (i2, irest...))
3,540✔
1683
end
1684

1685
@inline _toind(i1, irest::Tuple{}) = i1
×
1686
@inline _toind(i1, irest) = CartesianIndex(i1, irest...)
1,210✔
1687

1688
function findall(B::BitArray)
4,188✔
1689
    nnzB = count(B)
9,720✔
1690
    I = Vector{eltype(keys(B))}(undef, nnzB)
8,065✔
1691
    nnzB == 0 && return I
4,188✔
1692
    nnzB == length(B) && (allindices!(I, B); return I)
3,877✔
1693
    Bc = B.chunks
2,665✔
1694
    Bs = size(B)
50✔
1695
    Bi = i1 = i = 1
50✔
1696
    irest = ntuple(one, ndims(B) - 1)
50✔
1697
    c = Bc[1]
2,665✔
1698
    @inbounds while true
184,685✔
1699
        while c == 0
189,894✔
1700
            Bi == length(Bc) && return I
6,694✔
1701
            i1 += 64
4,029✔
1702
            Bi += 1
4,029✔
1703
            c = Bc[Bi]
4,029✔
1704
        end
4,029✔
1705

1706
        tz = trailing_zeros(c)
183,230✔
1707
        c = _blsr(c)
183,230✔
1708

1709
        i1, irest = _overflowind(i1 + tz, irest, Bs)
183,230✔
1710
        I[i] = _toind(i1, irest)
183,230✔
1711
        i += 1
183,230✔
1712
        i1 -= tz
183,230✔
1713
    end
183,230✔
1714
end
1715

1716
# For performance
1717
findall(::typeof(!iszero), B::BitArray) = findall(B)
1✔
1718

1719
## Reductions ##
1720

1721
_sum(A::BitArray, dims)    = reduce(+, A, dims=dims)
×
1722
_sum(B::BitArray, ::Colon) = count(B)
×
1723

1724
function all(B::BitArray)
547✔
1725
    isempty(B) && return true
2,237✔
1726
    Bc = B.chunks
2,234✔
1727
    @inbounds begin
1,029✔
1728
        for i = 1:length(Bc)-1
2,234✔
1729
            Bc[i] == _msk64 || return false
2,644✔
1730
        end
4,737✔
1731
        Bc[end] == _msk_end(B) || return false
2,668✔
1732
    end
1733
    return true
1,668✔
1734
end
1735

1736
function any(B::BitArray)
4,559✔
1737
    isempty(B) && return false
3,911,836✔
1738
    Bc = B.chunks
3,911,835✔
1739
    @inbounds begin
5,961✔
1740
        for i = 1:length(Bc)
3,911,835✔
1741
            Bc[i] == 0 || return true
7,794,034✔
1742
        end
30,476✔
1743
    end
1744
    return false
29,916✔
1745
end
1746

1747
minimum(B::BitArray) = isempty(B) ? throw(ArgumentError("argument must be non-empty")) : all(B)
1✔
1748
maximum(B::BitArray) = isempty(B) ? throw(ArgumentError("argument must be non-empty")) : any(B)
1✔
1749

1750
## map over bitarrays ##
1751

1752
# Specializing map is even more important for bitarrays than it is for generic
1753
# arrays since there can be a 64x speedup by working at the level of Int64
1754
# instead of looping bit-by-bit.
1755

1756
map(::Union{typeof(~), typeof(!)}, A::BitArray) = bit_map!(~, similar(A), A)
380✔
1757
map(::typeof(zero), A::BitArray) = fill!(similar(A), false)
14✔
1758
map(::typeof(one), A::BitArray) = fill!(similar(A), true)
14✔
1759
map(::typeof(identity), A::BitArray) = copy(A)
14✔
1760

1761
map!(::Union{typeof(~), typeof(!)}, dest::BitArray, A::BitArray) = bit_map!(~, dest, A)
393✔
1762
map!(::typeof(zero), dest::BitArray, A::BitArray) = fill!(dest, false)
14✔
1763
map!(::typeof(one), dest::BitArray, A::BitArray) = fill!(dest, true)
14✔
1764
map!(::typeof(identity), dest::BitArray, A::BitArray) = copyto!(dest, A)
14✔
1765

1766
for (T, f) in ((:(Union{typeof(&), typeof(*), typeof(min)}), :(&)),
1767
               (:(Union{typeof(|), typeof(max)}),            :(|)),
1768
               (:(Union{typeof(xor), typeof(!=)}),           :xor),
1769
               (:(typeof(nand)),                             :nand),
1770
               (:(typeof(nor)),                              :nor),
1771
               (:(Union{typeof(>=), typeof(^)}),             :((p, q) -> p | ~q)),
1,304✔
1772
               (:(typeof(<=)),                               :((p, q) -> ~p | q)),
652✔
1773
               (:(typeof(==)),                               :((p, q) -> ~xor(p, q))),
652✔
1774
               (:(typeof(<)),                                :((p, q) -> ~p & q)),
652✔
1775
               (:(typeof(>)),                                :((p, q) -> p & ~q)))
652✔
1776
    @eval map(::$T, A::BitArray, B::BitArray) = bit_map!($f, similar(A), A, B)
1,303✔
1777
    @eval map!(::$T, dest::BitArray, A::BitArray, B::BitArray) = bit_map!($f, dest, A, B)
1,276✔
1778
end
1779

1780
# If we were able to specialize the function to a known bitwise operation,
1781
# map across the chunks. Otherwise, fall-back to the AbstractArray method that
1782
# iterates bit-by-bit.
1783
function bit_map!(f::F, dest::BitArray, A::BitArray) where F
1784
    length(A) <= length(dest) || throw(DimensionMismatch("length of destination must be >= length of collection"))
773✔
1785
    isempty(A) && return dest
773✔
1786
    destc = dest.chunks
718✔
1787
    Ac = A.chunks
718✔
1788
    len_Ac = length(Ac)
718✔
1789
    for i = 1:(len_Ac-1)
718✔
1790
        destc[i] = f(Ac[i])
17,215✔
1791
    end
33,880✔
1792
    # the last effected UInt64's original content
1793
    dest_last = destc[len_Ac]
718✔
1794
    _msk = _msk_end(A)
718✔
1795
    # first zero out the bits mask is going to change
1796
    # then update bits by `or`ing with a masked RHS
1797
    # DO NOT SEPARATE ONTO TO LINES.
1798
    # Otherwise there will be bugs when Ac aliases destc
1799
    destc[len_Ac] = (dest_last & (~_msk)) | f(Ac[len_Ac]) & _msk
718✔
1800
    dest
718✔
1801
end
1802
function bit_map!(f::F, dest::BitArray, A::BitArray, B::BitArray) where F
2,579✔
1803
    min_bitlen = min(length(A), length(B))
2,579✔
1804
    min_bitlen <= length(dest) || throw(DimensionMismatch("length of destination must be >= length of smallest input collection"))
2,579✔
1805
    isempty(A) && return dest
2,579✔
1806
    isempty(B) && return dest
2,395✔
1807
    destc = dest.chunks
2,395✔
1808
    Ac = A.chunks
2,395✔
1809
    Bc = B.chunks
2,395✔
1810
    len_Ac = min(length(Ac), length(Bc))
2,395✔
1811
    for i = 1:len_Ac-1
2,395✔
1812
        destc[i] = f(Ac[i], Bc[i])
57,592✔
1813
    end
113,344✔
1814
    # the last effected UInt64's original content
1815
    dest_last = destc[len_Ac]
2,395✔
1816
    _msk = _msk_end(min_bitlen)
2,395✔
1817
    # first zero out the bits mask is going to change
1818
    # then update bits by `or`ing with a masked RHS
1819
    # DO NOT SEPARATE ONTO TO LINES.
1820
    # Otherwise there will be bugs when Ac or Bc aliases destc
1821
    destc[len_Ac] = (dest_last & ~(_msk)) | f(Ac[end], Bc[end]) & _msk
2,395✔
1822
    dest
2,395✔
1823
end
1824

1825
## Filter ##
1826

1827
function filter(f, Bs::BitArray)
×
1828
    boolmap::Array{Bool} = map(f, Bs)
×
1829
    Bs[boolmap]
×
1830
end
1831

1832

1833
## Concatenation ##
1834

1835
function hcat(B::BitVector...)
4✔
1836
    height = length(B[1])
4✔
1837
    for j = 2:length(B)
4✔
1838
        length(B[j]) == height ||
5✔
1839
            throw(DimensionMismatch("dimensions must match: $j-th argument has length $(length(B[j])), should have $height"))
1840
    end
3✔
1841
    M = BitMatrix(undef, height, length(B))
3✔
1842
    for j = 1:length(B)
3✔
1843
        copy_chunks!(M.chunks, (height*(j-1))+1, B[j].chunks, 1, height)
6✔
1844
    end
9✔
1845
    return M
3✔
1846
end
1847

1848
function vcat(V::BitVector...)
541✔
1849
    n = 0
541✔
1850
    for Vk in V
541✔
1851
        n += length(Vk)
2,094✔
1852
    end
2,635✔
1853
    B = BitVector(undef, n)
541✔
1854
    j = 1
541✔
1855
    for Vk in V
541✔
1856
        copy_chunks!(B.chunks, j, Vk.chunks, 1, length(Vk))
2,094✔
1857
        j += length(Vk)
2,094✔
1858
    end
2,635✔
1859
    return B
541✔
1860
end
1861

1862
function hcat(A::Union{BitMatrix,BitVector}...)
2✔
1863
    nargs = length(A)
2✔
1864
    nrows = size(A[1], 1)
2✔
1865
    ncols = 0
2✔
1866
    dense = true
2✔
1867
    for j = 1:nargs
2✔
1868
        Aj = A[j]
5✔
1869
        nd = ndims(Aj)
7✔
1870
        ncols += (nd==2 ? size(Aj,2) : 1)
5✔
1871
        size(Aj, 1) == nrows ||
6✔
1872
            throw(DimensionMismatch("row lengths must match: $j-th element has first dim $(size(Aj, 1)), should have $nrows"))
1873
    end
7✔
1874

1875
    B = BitMatrix(undef, nrows, ncols)
1✔
1876

1877
    pos = 1
1✔
1878
    for k = 1:nargs
1✔
1879
        Ak = A[k]
3✔
1880
        n = length(Ak)
4✔
1881
        copy_chunks!(B.chunks, pos, Ak.chunks, 1, n)
4✔
1882
        pos += n
3✔
1883
    end
5✔
1884
    return B
1✔
1885
end
1886

1887
function vcat(A::BitMatrix...)
127✔
1888
    nargs = length(A)
127✔
1889
    nrows, nrowsA = 0, sizehint!(Int[], nargs)
127✔
1890
    for a in A
127✔
1891
        sz1 = size(a, 1)
1,265✔
1892
        nrows += sz1
1,265✔
1893
        push!(nrowsA, sz1)
1,265✔
1894
    end
1,388✔
1895
    ncols = size(A[1], 2)
127✔
1896
    for j = 2:nargs
127✔
1897
        size(A[j], 2) == ncols ||
1,139✔
1898
        throw(DimensionMismatch("column lengths must match: $j-th element has second dim $(size(A[j], 2)), should have $ncols"))
1899
    end
2,152✔
1900
    B = BitMatrix(undef, nrows, ncols)
126✔
1901
    Bc = B.chunks
126✔
1902
    pos_d = 1
126✔
1903
    pos_s = fill(1, nargs)
1,262✔
1904
    for j = 1:ncols, k = 1:nargs
126✔
1905
        copy_chunks!(Bc, pos_d, A[k].chunks, pos_s[k], nrowsA[k])
20,839✔
1906
        pos_s[k] += nrowsA[k]
20,839✔
1907
        pos_d += nrowsA[k]
20,839✔
1908
    end
22,205✔
1909
    return B
126✔
1910
end
1911

1912
# general case, specialized for BitArrays and Integers
1913
_cat(dims::Integer, X::Union{BitArray, Bool}...) = _cat(Int(dims)::Int, X...)
×
1914
function _cat(dims::Int, X::Union{BitArray, Bool}...)
4✔
1915
    dims = Int(dims)
4✔
1916
    catdims = dims2cat(dims)
8✔
1917
    shape = cat_shape(catdims, map(cat_size, X))
4✔
1918
    A = falses(shape)
4✔
1919
    return __cat(A, shape, catdims, X...)
4✔
1920
end
1921

1922
# hvcat -> use fallbacks in abstractarray.jl
1923

1924

1925
# BitArray I/O
1926

1927
write(s::IO, B::BitArray) = write(s, B.chunks)
3✔
1928
function read!(s::IO, B::BitArray)
7✔
1929
    n = length(B)
7✔
1930
    Bc = B.chunks
7✔
1931
    nc = length(read!(s, Bc))
7✔
1932
    if length(Bc) > 0 && Bc[end] & _msk_end(n) ≠ Bc[end]
5✔
1933
        Bc[end] &= _msk_end(n) # ensure that the BitArray is not broken
2✔
1934
        throw(DimensionMismatch("read mismatch, found non-zero bits after BitArray length"))
2✔
1935
    end
1936
    return B
3✔
1937
end
1938

1939
sizeof(B::BitArray) = sizeof(B.chunks)
2✔
1940

1941
function _split_rest(a::Union{Vector, BitVector}, n::Int)
6✔
1942
    _check_length_split_rest(length(a), n)
6✔
1943
    last_n = a[end-n+1:end]
10✔
1944
    resize!(a, length(a) - n)
5✔
1945
    return a, last_n
5✔
1946
end
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc