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

JuliaLang / julia / 1384

23 Dec 2025 05:50AM UTC coverage: 76.631%. First build
1384

push

buildkite

web-flow
Fix JET warnings in `copy_chunks!`, `copy_chunks_rtol!`, `fill_chunks!` (#60453)

> local variable `msk_d1` may be undefined: msk_d1::UInt64

The code logic was actually right, but by transforming the code, JET can
also see it (and arguably it is now also easier for a human to see that
everything is correct)

3 of 13 new or added lines in 1 file covered. (23.08%)

62365 of 81383 relevant lines covered (76.63%)

22310167.31 hits per line

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

75.43
/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
8✔
29
        n = 1
122,653✔
30
        i = 1
122,653✔
31
        for d in dims
741,112✔
32
            d >= 0 || throw(ArgumentError("dimension size must be ≥ 0, got $d for dimension $i"))
2,390,332✔
33
            n *= d
2,390,332✔
34
            i += 1
285,825✔
35
        end
825,222✔
36
        nc = num_bit_chunks(n)
2,307,390✔
37
        chunks = Vector{UInt64}(undef, nc)
2,307,916✔
38
        nc > 0 && (chunks[end] = UInt64(0))
2,307,444✔
39
        b = new(chunks, n)
2,307,916✔
40
        N != 1 && (b.dims = dims)
202,937✔
41
        return b
580,678✔
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
```jldoctest; filter = r"[01]"
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))
9✔
70
BitArray{N}(::UndefInitializer, dims::Integer...) where {N} = BitArray{N}(undef, map(Int,dims))::BitArray{N}
3✔
71
BitArray(::UndefInitializer, dims::NTuple{N,Integer}) where {N} = BitArray{N}(undef, map(Int, dims)...)
1,835,922✔
72
BitArray{N}(::UndefInitializer, dims::NTuple{N,Integer}) where {N} = BitArray{N}(undef, map(Int, dims)...)
3✔
73

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

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

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

82
Construct a `BitVector` from a tuple of `Bool`.
83
# Examples
84
```jldoctest
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}})
18✔
97
    bv = BitVector(undef, length(nt))
18✔
98
    bv .= nt
18✔
99
end
100

101
## utility functions ##
102

103
length(B::BitArray) = B.len
337,064,597✔
104
size(B::BitVector) = (B.len,)
226,667,179✔
105
size(B::BitArray) = B.dims
86,925,248✔
106

107
isassigned(B::BitArray, i::Int) = 1 <= i <= length(B)
8,703✔
108

109
IndexStyle(::Type{<:BitArray}) = IndexLinear()
3,058,662✔
110

111
## aux functions ##
112

113
const _msk64 = ~UInt64(0)
114
@inline _div64(l) = l >> 6
949,200,780✔
115
@inline _mod64(l) = l & 63
945,816,564✔
116
@inline _blsr(x)= x & (x-1) #zeros the last set bit. Has native instruction on many archs. needed in multidimensional.jl
5,943,175✔
117
@inline _msk_end(l::Int) = _msk64 >>> _mod64(-l)
2,013,929✔
118
@inline _msk_end(B::BitArray) = _msk_end(length(B))
667,181✔
119
num_bit_chunks(n::Int) = _div64(n+63)
3,600,519✔
120

121
@inline get_chunks_id(i::Int) = _div64(i-1)+1, _mod64(i-1)
692,297,588✔
122

123
function glue_src_bitchunks(src::Vector{UInt64}, k::Int, ks1::Int, msk_s0::UInt64, ls0::Int)
×
124
    @inbounds begin
×
125
        chunk = ((src[k] & msk_s0) >>> ls0)
×
126
        if ks1 > k && ls0 > 0
×
127
            chunk_n = (src[k + 1] & ~msk_s0)
×
128
            chunk |= (chunk_n << (64 - ls0))
×
129
        end
130
    end
131
    return chunk
×
132
end
133

134
function copy_chunks!(dest::Vector{UInt64}, pos_d::Int, src::Vector{UInt64}, pos_s::Int, numbits::Int)
×
135
    numbits == 0 && return
×
136
    if dest === src && pos_d > pos_s
×
137
        return copy_chunks_rtol!(dest, pos_d, pos_s, numbits)
×
138
    end
139

140
    kd0, ld0 = get_chunks_id(pos_d)
×
141
    kd1, ld1 = get_chunks_id(pos_d + numbits - 1)
×
142
    ks0, ls0 = get_chunks_id(pos_s)
×
143
    ks1, ls1 = get_chunks_id(pos_s + numbits - 1)
×
144

145
    delta_kd = kd1 - kd0
×
146
    delta_ks = ks1 - ks0
×
147

148
    u = _msk64
×
NEW
149
    msk_d0 = ~(u << ld0)
×
NEW
150
    msk_d1 = (u << (ld1+1))
×
151
    if delta_kd == 0
×
NEW
152
        msk_d0 |= msk_d1
×
153
    end
NEW
154
    msk_s0 = (u << ls0)
×
155
    if delta_ks == 0
×
NEW
156
        msk_s0 &= ~(u << (ls1+1))
×
157
    end
158

159
    chunk_s0 = glue_src_bitchunks(src, ks0, ks1, msk_s0, ls0)
×
160

161
    dest[kd0] = (dest[kd0] & msk_d0) | ((chunk_s0 << ld0) & ~msk_d0)
×
162

163
    delta_kd == 0 && return
×
164

165
    for i = 1 : kd1 - kd0 - 1
×
166
        chunk_s1 = glue_src_bitchunks(src, ks0 + i, ks1, msk_s0, ls0)
×
167

168
        chunk_s = (chunk_s0 >>> (64 - ld0)) | (chunk_s1 << ld0)
×
169

170
        dest[kd0 + i] = chunk_s
×
171

172
        chunk_s0 = chunk_s1
×
173
    end
×
174

175
    if ks1 >= ks0 + delta_kd
×
176
        chunk_s1 = glue_src_bitchunks(src, ks0 + delta_kd, ks1, msk_s0, ls0)
×
177
    else
178
        chunk_s1 = UInt64(0)
×
179
    end
180

181
    chunk_s = (chunk_s0 >>> (64 - ld0)) | (chunk_s1 << ld0)
×
182

183
    dest[kd1] = (dest[kd1] & msk_d1) | (chunk_s & ~msk_d1)
×
184

185
    return
×
186
end
187

188
function copy_chunks_rtol!(chunks::Vector{UInt64}, pos_d::Int, pos_s::Int, numbits::Int)
×
189
    pos_d == pos_s && return
×
190
    pos_d < pos_s && return copy_chunks!(chunks, pos_d, chunks, pos_s, numbits)
×
191

192
    left = numbits
×
193
    s = min(left, 64)
×
194
    b = left - s
×
195
    ps = pos_s + b
×
196
    pd = pos_d + b
×
197
    u = _msk64
×
198
    while left > 0
×
199
        kd0, ld0 = get_chunks_id(pd)
×
200
        kd1, ld1 = get_chunks_id(pd + s - 1)
×
201
        ks0, ls0 = get_chunks_id(ps)
×
202
        ks1, ls1 = get_chunks_id(ps + s - 1)
×
203

204
        delta_kd = kd1 - kd0
×
205
        delta_ks = ks1 - ks0
×
206

NEW
207
        msk_d0 = ~(u << ld0)
×
NEW
208
        msk_d1 = (u << (ld1+1))
×
209
        if delta_kd == 0
×
NEW
210
            msk_d0 |= msk_d1
×
211
        end
NEW
212
        msk_s0 = (u << ls0)
×
213
        if delta_ks == 0
×
NEW
214
            msk_s0 &= ~(u << (ls1+1))
×
215
        end
216

217
        chunk_s0 = glue_src_bitchunks(chunks, ks0, ks1, msk_s0, ls0) & ~(u << s)
×
218
        chunks[kd0] = (chunks[kd0] & msk_d0) | ((chunk_s0 << ld0) & ~msk_d0)
×
219

220
        if delta_kd != 0
×
221
            chunk_s = (chunk_s0 >>> (64 - ld0))
×
222

223
            chunks[kd1] = (chunks[kd1] & msk_d1) | (chunk_s & ~msk_d1)
×
224
        end
225

226
        left -= s
×
227
        s = min(left, 64)
×
228
        b = left - s
×
229
        ps = pos_s + b
×
230
        pd = pos_d + b
×
231
    end
×
232
end
233

234
function fill_chunks!(Bc::Array{UInt64}, x::Bool, pos::Int, numbits::Int)
47✔
235
    numbits <= 0 && return
47✔
236
    k0, l0 = get_chunks_id(pos)
47✔
237
    k1, l1 = get_chunks_id(pos+numbits-1)
47✔
238

239
    u = _msk64
47✔
240
    msk0 = (u << l0)
47✔
241
    msk1 = ~(u << (l1+1))
47✔
242
    if k1 == k0
47✔
243
        msk0 &= msk1
47✔
244
    end
245
    @inbounds if x
47✔
246
        Bc[k0] |= msk0
12✔
247
        for k = k0+1:k1-1
12✔
248
            Bc[k] = u
×
249
        end
×
250
        k1 > k0 && (Bc[k1] |= msk1)
12✔
251
    else
252
        Bc[k0] &= ~msk0
35✔
253
        for k = k0+1:k1-1
35✔
254
            Bc[k] = 0
×
255
        end
×
256
        k1 > k0 && (Bc[k1] &= ~msk1)
82✔
257
    end
258
end
259

260
copy_to_bitarray_chunks!(dest::Vector{UInt64}, pos_d::Int, src::BitArray, pos_s::Int, numbits::Int) =
1,235,423✔
261
    copy_chunks!(dest, pos_d, src.chunks, pos_s, numbits)
262

263
# pack 8 Bools encoded as one contiguous UIn64 into a single byte, e.g.:
264
# 0000001:0000001:00000000:00000000:00000001:00000000:00000000:00000001 → 11001001 → 0xc9
265
function pack8bools(z::UInt64)
266
    z |= z >>> 7
192✔
267
    z |= z >>> 14
192✔
268
    z |= z >>> 28
192✔
269
    z &= 0xFF
192✔
270
    return z
×
271
end
272

273
function copy_to_bitarray_chunks!(Bc::Vector{UInt64}, pos_d::Int, C::Array{Bool}, pos_s::Int, numbits::Int)
9✔
274
    kd0, ld0 = get_chunks_id(pos_d)
9✔
275
    kd1, ld1 = get_chunks_id(pos_d + numbits - 1)
9✔
276

277
    delta_kd = kd1 - kd0
9✔
278

279
    u = _msk64
9✔
280
    if delta_kd == 0
9✔
281
        msk_d0 = msk_d1 = ~(u << ld0) | (u << (ld1+1))
3✔
282
        lt0 = ld1
3✔
283
    else
284
        msk_d0 = ~(u << ld0)
6✔
285
        msk_d1 = (u << (ld1+1))
6✔
286
        lt0 = 63
6✔
287
    end
288

289
    bind = kd0
9✔
290
    ind = pos_s
9✔
291
    @inbounds if ld0 > 0
9✔
292
        c = UInt64(0)
×
293
        for j = ld0:lt0
×
294
            c |= (UInt64(C[ind]) << j)
×
295
            ind += 1
×
296
        end
×
297
        Bc[kd0] = (Bc[kd0] & msk_d0) | (c & ~msk_d0)
×
298
        bind += 1
×
299
    end
300

301
    nc = _div64(numbits - ind + pos_s)
9✔
302
    nc8 = (nc >>> 3) << 3
9✔
303
    if nc8 > 0
9✔
304
        ind8 = 1
3✔
305
        P8 = Ptr{UInt64}(pointer(C, ind)) # unaligned i64 pointer
3✔
306
        @inbounds for i = 1:nc8
3✔
307
            c = UInt64(0)
24✔
308
            for j = 0:7
24✔
309
                # unaligned load
310
                c |= (pack8bools(unsafe_load(P8, ind8)) << (j<<3))
192✔
311
                ind8 += 1
192✔
312
            end
360✔
313
            Bc[bind] = c
24✔
314
            bind += 1
24✔
315
        end
45✔
316
        ind += (ind8-1) << 3
3✔
317
    end
318
    @inbounds for i = (nc8+1):nc
12✔
319
        c = UInt64(0)
30✔
320
        for j = 0:63
30✔
321
            c |= (UInt64(C[ind]) << j)
1,920✔
322
            ind += 1
1,920✔
323
        end
3,810✔
324
        Bc[bind] = c
30✔
325
        bind += 1
30✔
326
    end
54✔
327
    @inbounds if bind ≤ kd1
9✔
328
        @assert bind == kd1
9✔
329
        c = UInt64(0)
9✔
330
        for j = 0:ld1
9✔
331
            c |= (UInt64(C[ind]) << j)
87✔
332
            ind += 1
87✔
333
        end
165✔
334
        Bc[kd1] = (Bc[kd1] & msk_d1) | (c & ~msk_d1)
9✔
335
    end
336
end
337

338
## More definitions in multidimensional.jl
339

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

343
const bitcache_chunks = 64 # this can be changed
344
const bitcache_size = 64 * bitcache_chunks # do not change this
345

346
dumpbitcache(Bc::Vector{UInt64}, bind::Int, C::Vector{Bool}) =
271,841✔
347
    copy_to_bitarray_chunks!(Bc, ((bind - 1) << 6) + 1, C, 1, min(bitcache_size, (length(Bc)-bind+1) << 6))
348

349

350
## custom iterator ##
351
function iterate(B::BitArray, i::Int=0)
21,168✔
352
    i >= length(B) && return nothing
241,725,424✔
353
    (B.chunks[_div64(i)+1] & (UInt64(1)<<_mod64(i)) != 0, i+1)
240,141,905✔
354
end
355

356
## similar, fill!, copy! etc ##
357

358
similar(B::BitArray) = BitArray(undef, size(B))
445,989✔
359
similar(B::BitArray, dims::Int...) = BitArray(undef, dims)
3✔
360
similar(B::BitArray, dims::Dims) = BitArray(undef, dims...)
3✔
361

362
similar(B::BitArray, T::Type{Bool}, dims::Dims) = BitArray(undef, dims)
288,365✔
363
# changing type to a non-Bool returns an Array
364
# (this triggers conversions like float(bitvector) etc.)
365
similar(B::BitArray, T::Type, dims::Dims) = Array{T}(undef, dims)
37,983✔
366

367
function fill!(B::BitArray, x)
109,257✔
368
    y = convert(Bool, x)
109,257✔
369
    isempty(B) && return B
109,257✔
370
    Bc = B.chunks
109,255✔
371
    if !y
109,255✔
372
        fill!(Bc, 0)
109,584✔
373
    else
374
        fill!(Bc, _msk64)
1,006✔
375
        Bc[end] &= _msk_end(B)
552✔
376
    end
377
    return B
109,255✔
378
end
379

380
"""
381
    falses(dims)
382

383
Create a `BitArray` with all values set to `false`.
384

385
# Examples
386
```jldoctest
387
julia> falses(2,3)
388
2×3 BitMatrix:
389
 0  0  0
390
 0  0  0
391
```
392
"""
393
falses(dims::DimOrInd...) = falses(dims)
243,279✔
394
falses(dims::NTuple{N, Union{Integer, OneTo}}) where {N} = falses(map(to_dim, dims))
27✔
395
falses(dims::NTuple{N, Integer}) where {N} = fill!(BitArray(undef, dims), false)
243,237✔
396
falses(dims::Tuple{}) = fill!(BitArray(undef, dims), false)
21✔
397
falses(dims::NTuple{N, DimOrInd}) where {N} = fill!(similar(BitArray, dims), false)
12✔
398

399
"""
400
    trues(dims)
401

402
Create a `BitArray` with all values set to `true`.
403

404
# Examples
405
```jldoctest
406
julia> trues(2,3)
407
2×3 BitMatrix:
408
 1  1  1
409
 1  1  1
410
```
411
"""
412
trues(dims::DimOrInd...) = trues(dims)
28,617✔
413
trues(dims::NTuple{N, Union{Integer, OneTo}}) where {N} = trues(map(to_dim, dims))
×
414
trues(dims::NTuple{N, Integer}) where {N} = fill!(BitArray(undef, dims), true)
28,653✔
415
trues(dims::Tuple{}) = fill!(BitArray(undef, dims), true)
9✔
416
trues(dims::NTuple{N, DimOrInd}) where {N} = fill!(similar(BitArray, dims), true)
6✔
417

418
function one(x::BitMatrix)
×
419
    m, n = size(x)
×
420
    m == n || throw(DimensionMismatch("multiplicative identity defined only for square matrices"))
×
421
    a = falses(n, n)
×
422
    for i = 1:n
×
423
        a[i,i] = true
×
424
    end
×
425
    return a
×
426
end
427

428
function copyto!(dest::BitArray, src::BitArray)
102✔
429
    length(src) > length(dest) && throw(BoundsError(dest, length(dest)+1))
102✔
430
    destc = dest.chunks; srcc = src.chunks
102✔
431
    nc = min(length(destc), length(srcc))
102✔
432
    nc == 0 && return dest
102✔
433
    @inbounds begin
102✔
434
        for i = 1 : nc - 1
102✔
435
            destc[i] = srcc[i]
17,127✔
436
        end
34,155✔
437
        if length(src) == length(dest)
102✔
438
            destc[nc] = srcc[nc]
102✔
439
        else
440
            msk_s = _msk_end(src)
×
441
            msk_d = ~msk_s
×
442
            destc[nc] = (msk_d & destc[nc]) | (msk_s & srcc[nc])
×
443
        end
444
    end
445
    return dest
102✔
446
end
447

448
function unsafe_copyto!(dest::BitArray, doffs::Integer, src::Union{BitArray,Array}, soffs::Integer, n::Integer)
449
    copy_to_bitarray_chunks!(dest.chunks, Int(doffs), src, Int(soffs), Int(n))
186,573✔
450
    return dest
186,573✔
451
end
452

453
copyto!(dest::BitArray, doffs::Integer, src::Union{BitArray,Array}, soffs::Integer, n::Integer) =
426,582✔
454
    _copyto_int!(dest, Int(doffs), src, Int(soffs), Int(n))
455
function _copyto_int!(dest::BitArray, doffs::Int, src::Union{BitArray,Array}, soffs::Int, n::Int)
426,582✔
456
    n == 0 && return dest
426,582✔
457
    n < 0 && throw(ArgumentError("Number of elements to copy must be non-negative."))
426,192✔
458
    soffs < 1 && throw(BoundsError(src, soffs))
426,189✔
459
    doffs < 1 && throw(BoundsError(dest, doffs))
426,186✔
460
    soffs+n-1 > length(src) && throw(BoundsError(src, length(src)+1))
426,177✔
461
    doffs+n-1 > length(dest) && throw(BoundsError(dest, length(dest)+1))
251,067✔
462
    return unsafe_copyto!(dest, doffs, src, soffs, n)
186,561✔
463
end
464

465
function copyto!(dest::BitArray, src::Array)
15✔
466
    length(src) > length(dest) && throw(BoundsError(dest, length(dest)+1))
15✔
467
    length(src) == 0 && return dest
15✔
468
    return unsafe_copyto!(dest, 1, src, 1, length(src))
12✔
469
end
470

471
function reshape(B::BitArray{N}, dims::NTuple{N,Int}) where N
12✔
472
    return dims == size(B) ? B : _bitreshape(B, dims)
21✔
473
end
474
reshape(B::BitArray, dims::Tuple{Vararg{Int}}) = _bitreshape(B, dims)
297✔
475
function _bitreshape(B::BitArray, dims::NTuple{N,Int}) where N
24✔
476
    prod(dims) == length(B) ||
318✔
477
        throw(DimensionMismatch("new dimensions $(dims) must be consistent with array length $(length(B))"))
478
    Br = BitArray{N}(undef, ntuple(i->0,Val(N))...)
306✔
479
    Br.chunks = B.chunks
306✔
480
    Br.len = prod(dims)
306✔
481
    N != 1 && (Br.dims = dims)
306✔
482
    return Br
306✔
483
end
484

485
## Constructors ##
486

487
function Array{T,N}(B::BitArray{N}) where {T,N}
5,760✔
488
    A = Array{T,N}(undef, size(B))
806,556✔
489
    Bc = B.chunks
806,556✔
490
    @inbounds for i = 1:length(A)
806,556✔
491
        A[i] = unsafe_bitgetindex(Bc, i)
291,909,748✔
492
    end
583,018,685✔
493
    return A
560,916✔
494
end
495

496
BitArray(A::AbstractArray{<:Any,N}) where {N} = BitArray{N}(A)
44,063✔
497

498
function BitArray{N}(A::AbstractArray{T,N}) where N where T
120✔
499
    B = BitArray(undef, convert(Dims{N}, size(A)::Dims{N}))
62,396✔
500
    _checkaxs(axes(B), axes(A))
62,396✔
501
    _copyto_bitarray!(B, A)
62,390✔
502
    return B::BitArray{N}
56,108✔
503
end
504

505
function _copyto_bitarray!(B::BitArray, A::AbstractArray)
74,915✔
506
    l = length(A)
74,924✔
507
    l == 0 && return B
74,924✔
508
    l > length(B) && throw(BoundsError(B, length(B)+1))
71,783✔
509
    Bc = B.chunks
71,783✔
510
    nc = num_bit_chunks(l)
71,783✔
511
    Ai = first(eachindex(A))
71,783✔
512
    @inbounds begin
71,783✔
513
        for i = 1:nc-1
71,786✔
514
            c = UInt64(0)
758,493✔
515
            for j = 0:63
758,493✔
516
                c |= (UInt64(convert(Bool, A[Ai])::Bool) << j)
49,905,184✔
517
                Ai = nextind(A, Ai)
48,543,552✔
518
            end
96,328,611✔
519
            Bc[i] = c
758,493✔
520
        end
1,458,105✔
521
        c = UInt64(0)
71,783✔
522
        tail = _mod64(l - 1) + 1
71,783✔
523
        for j = 0:tail-1
71,786✔
524
            c |= (UInt64(convert(Bool, A[Ai])::Bool) << j)
3,190,200✔
525
            Ai = nextind(A, Ai)
2,535,471✔
526
        end
4,999,165✔
527
        msk = _msk_end(tail)
71,777✔
528
        Bc[nc] = (c & msk) | (Bc[nc] & ~msk)
71,777✔
529
    end
530
    return B
71,777✔
531
end
532

533
reinterpret(::Type{Bool}, B::BitArray, dims::NTuple{N,Int}) where {N} = reinterpret(B, dims)
×
534
reinterpret(B::BitArray, dims::NTuple{N,Int}) where {N} = reshape(B, dims)
×
535

536
(::Type{T})(x::T) where {T<:BitArray} = copy(x)::T
3✔
537
BitArray(x::BitArray) = copy(x)
219✔
538

539
"""
540
    BitArray(itr)
541

542
Construct a [`BitArray`](@ref) generated by the given iterable object.
543
The shape is inferred from the `itr` object.
544

545
# Examples
546
```jldoctest
547
julia> BitArray([1 0; 0 1])
548
2×2 BitMatrix:
549
 1  0
550
 0  1
551

552
julia> BitArray(x+y == 3 for x = 1:2, y = 1:3)
553
2×3 BitMatrix:
554
 0  1  0
555
 1  0  0
556

557
julia> BitArray(x+y == 3 for x = 1:2 for y = 1:3)
558
6-element BitVector:
559
 0
560
 1
561
 0
562
 1
563
 0
564
 0
565
```
566
"""
567
BitArray(itr) = gen_bitarray(IteratorSize(itr), itr)
30✔
568
BitArray{N}(itr) where N = gen_bitarrayN(BitArray{N}, IteratorSize(itr), itr)
274,967✔
569

570
convert(::Type{T}, a::AbstractArray) where {T<:BitArray} = a isa T ? a : T(a)::T
261,651✔
571

572
# generic constructor from an iterable without compile-time info
573
# (we pass start(itr) explicitly to avoid a type-instability with filters)
574
gen_bitarray(isz::IteratorSize, itr) = gen_bitarray_from_itr(itr)
12,534✔
575

576
# generic iterable with known shape
577
function gen_bitarray(::HasShape, itr)
578
    B = BitArray(undef, size(itr))
12✔
579
    for (I,x) in zip(CartesianIndices(axes(itr)), itr)
12✔
580
        B[I] = x
12✔
581
    end
12✔
582
    return B
12✔
583
end
584

585
# generator with known shape or length
586
function gen_bitarray(::HasShape, itr::Generator)
6✔
587
    B = BitArray(undef, size(itr))
262,439✔
588
    return fill_bitarray_from_itr!(B, itr)
262,439✔
589
end
590
function gen_bitarray(::HasLength, itr)
×
591
    b = BitVector(undef, length(itr))
×
592
    return fill_bitarray_from_itr!(b, itr)
×
593
end
594

595
gen_bitarray(::IsInfinite, itr) =  throw(ArgumentError("infinite-size iterable used in BitArray constructor"))
3✔
596

597
gen_bitarrayN(::Type{BitVector}, itsz, itr)                        = gen_bitarray(itsz, itr)
12,528✔
598
gen_bitarrayN(::Type{BitVector}, itsz::HasShape{1}, itr)           = gen_bitarray(itsz, itr)
262,430✔
599
gen_bitarrayN(::Type{BitArray{N}}, itsz::HasShape{N}, itr) where N = gen_bitarray(itsz, itr)
×
600
# The first of these is just for ambiguity resolution
601
gen_bitarrayN(::Type{BitVector}, itsz::HasShape{N}, itr) where N      = throw(DimensionMismatch("cannot create a BitVector from a $N-dimensional iterator"))
6✔
602
gen_bitarrayN(@nospecialize(T::Type), itsz::HasShape{N}, itr) where N = throw(DimensionMismatch("cannot create a $T from a $N-dimensional iterator"))
3✔
603
gen_bitarrayN(@nospecialize(T::Type), itsz, itr) = throw(DimensionMismatch("cannot create a $T from a generic iterator"))
×
604

605
# The aux functions gen_bitarray_from_itr and fill_bitarray_from_itr! both
606
# use a Vector{Bool} cache for performance reasons
607

608
function gen_bitarray_from_itr(itr)
12,534✔
609
    B = empty!(BitVector(undef, bitcache_size))
802,176✔
610
    C = Vector{Bool}(undef, bitcache_size)
12,534✔
611
    Bc = B.chunks
12,534✔
612
    ind = 1
12,534✔
613
    cind = 1
12,534✔
614
    y = iterate(itr)
23,502✔
615
    while y !== nothing
917,901✔
616
        x, st = y
905,367✔
617
        @inbounds C[ind] = x
905,367✔
618
        ind += 1
905,367✔
619
        if ind > bitcache_size
905,367✔
620
            resize!(B, length(B) + bitcache_size)
×
621
            dumpbitcache(Bc, cind, C)
×
622
            cind += bitcache_chunks
×
623
            ind = 1
×
624
        end
625
        y = iterate(itr, st)
1,798,749✔
626
    end
905,367✔
627
    if ind > 1
12,534✔
628
        @inbounds C[ind:bitcache_size] .= false
44,019,561✔
629
        resize!(B, length(B) + ind - 1)
10,968✔
630
        dumpbitcache(Bc, cind, C)
10,968✔
631
    end
632
    return B
12,534✔
633
end
634

635
function fill_bitarray_from_itr!(B::BitArray, itr)
262,439✔
636
    n = length(B)
262,439✔
637
    C = Vector{Bool}(undef, bitcache_size)
262,439✔
638
    Bc = B.chunks
262,439✔
639
    ind = 1
262,439✔
640
    cind = 1
262,439✔
641
    y = iterate(itr)
523,312✔
642
    while y !== nothing
25,593,690✔
643
        x, st = y
25,331,251✔
644
        @inbounds C[ind] = x
25,331,251✔
645
        ind += 1
25,331,251✔
646
        if ind > bitcache_size
25,331,251✔
647
            dumpbitcache(Bc, cind, C)
×
648
            cind += bitcache_chunks
×
649
            ind = 1
×
650
        end
651
        y = iterate(itr, st)
50,401,629✔
652
    end
25,331,251✔
653
    if ind > 1
262,439✔
654
        @inbounds C[ind:bitcache_size] .= false
1,043,204,557✔
655
        dumpbitcache(Bc, cind, C)
260,873✔
656
    end
657
    return B
262,439✔
658
end
659

660

661
## Indexing: getindex ##
662

663
@inline function unsafe_bitgetindex(Bc::Vector{UInt64}, i::Int)
6✔
664
    i1, i2 = get_chunks_id(i)
596,430,093✔
665
    u = UInt64(1) << i2
596,301,903✔
666
    @inbounds r = (Bc[i1] & u) != 0
596,430,093✔
667
    return r
420,249,300✔
668
end
669

670
@inline function getindex(B::BitArray, i::Int)
3,546✔
671
    @boundscheck checkbounds(B, i)
259,748,978✔
672
    unsafe_bitgetindex(B.chunks, i)
259,748,978✔
673
end
674

675
## Indexing: setindex! ##
676

677
@inline function unsafe_bitsetindex!(Bc::Array{UInt64}, x::Bool, i::Int)
6✔
678
    i1, i2 = get_chunks_id(i)
95,723,740✔
679
    _unsafe_bitsetindex!(Bc, x, i1, i2)
95,723,740✔
680
end
681

682
@inline function _unsafe_bitsetindex!(Bc::Array{UInt64}, x::Bool, i1::Int, i2::Int)
6✔
683
    u = UInt64(1) << i2
104,844,658✔
684
    @inbounds begin
7,539,900✔
685
        c = Bc[i1]
104,844,709✔
686
        Bc[i1] = ifelse(x, c | u, c & ~u)
104,844,709✔
687
    end
688
end
689

690
@inline function setindex!(B::BitArray, x, i::Int)
6,075✔
691
    @boundscheck checkbounds(B, i)
50,937,477✔
692
    unsafe_bitsetindex!(B.chunks, convert(Bool, x), i)
50,937,477✔
693
    return B
50,685,922✔
694
end
695

696
indexoffset(i) = first(i)-1
298,240✔
697
indexoffset(::Colon) = 0
×
698

699
@propagate_inbounds function setindex!(B::BitArray, X::AbstractArray, J0::Union{Colon,AbstractUnitRange{Int}})
102✔
700
    _setindex!(IndexStyle(B), B, X, to_indices(B, (J0,))[1])
102✔
701
end
702

703
# Assigning an array of bools is more complicated, but we can still do some
704
# work on chunks by combining X and I 64 bits at a time to improve perf by ~40%
705
@inline function setindex!(B::BitArray, X::AbstractArray, I::BitArray)
9✔
706
    @boundscheck checkbounds(B, I)
9✔
707
    _unsafe_setindex!(B, X, I)
9✔
708
end
709
function _unsafe_setindex!(B::BitArray, X::AbstractArray, I::BitArray)
9✔
710
    Bc = B.chunks
9✔
711
    Ic = I.chunks
9✔
712
    length(Bc) == length(Ic) || throw_boundserror(B, I)
9✔
713
    lc = length(Bc)
9✔
714
    lx = length(X)
9✔
715
    last_chunk_len = _mod64(length(B)-1)+1
9✔
716

717
    Xi = first(eachindex(X))
9✔
718
    lastXi = last(eachindex(X))
9✔
719
    for i = 1:lc
9✔
720
        @inbounds Imsk = Ic[i]
537✔
721
        @inbounds C = Bc[i]
537✔
722
        u = UInt64(1)
537✔
723
        for j = 1:(i < lc ? 64 : last_chunk_len)
537✔
724
            if Imsk & u != 0
34,020✔
725
                Xi > lastXi && throw_setindex_mismatch(X, count(I))
17,124✔
726
                @inbounds x = convert(Bool, X[Xi])
17,124✔
727
                C = ifelse(x, C | u, C & ~u)
17,124✔
728
                Xi = nextind(X, Xi)
17,124✔
729
            end
730
            u <<= 1
34,020✔
731
        end
67,503✔
732
        @inbounds Bc[i] = C
537✔
733
    end
1,065✔
734
    if Xi != nextind(X, lastXi)
9✔
735
        throw_setindex_mismatch(X, count(I))
×
736
    end
737
    return B
9✔
738
end
739

740
## Dequeue functionality ##
741

742
function push!(B::BitVector, item)
780✔
743
    # convert first so we don't grow the bitarray if the assignment won't work
744
    item = convert(Bool, item)
780✔
745

746
    Bc = B.chunks
780✔
747

748
    l = _mod64(length(B))
780✔
749
    if l == 0
780✔
750
        _growend!(Bc, 1)
15✔
751
        Bc[end] = UInt64(0)
15✔
752
    end
753
    B.len += 1
780✔
754
    if item
780✔
755
        B[end] = true
385✔
756
    end
757
    return B
780✔
758
end
759

760
function append!(B::BitVector, items::BitVector)
761
    n0 = length(B)
31,428✔
762
    n1 = length(items)
31,428✔
763
    n1 == 0 && return B
31,428✔
764
    Bc = B.chunks
27,504✔
765
    k0 = length(Bc)
27,504✔
766
    k1 = num_bit_chunks(n0 + n1)
27,504✔
767
    if k1 > k0
27,504✔
768
        _growend!(Bc, k1 - k0)
23,568✔
769
        Bc[end] = UInt64(0)
23,568✔
770
    end
771
    B.len += n1
27,504✔
772
    copy_chunks!(Bc, n0+1, items.chunks, 1, n1)
27,504✔
773
    return B
27,504✔
774
end
775

776
append!(B::BitVector, items) = append!(B, BitVector(items))
31,320✔
777
append!(A::Vector{Bool}, items::BitVector) = append!(A, Array(items))
×
778

779
function prepend!(B::BitVector, items::BitVector)
×
780
    n0 = length(B)
×
781
    n1 = length(items)
×
782
    n1 == 0 && return B
×
783
    Bc = B.chunks
×
784
    k0 = length(Bc)
×
785
    k1 = num_bit_chunks(n0 + n1)
×
786
    if k1 > k0
×
787
        _growend!(Bc, k1 - k0)
×
788
        Bc[end] = UInt64(0)
×
789
    end
790
    B.len += n1
×
791
    copy_chunks!(Bc, 1 + n1, Bc, 1, n0)
×
792
    copy_chunks!(Bc, 1, items.chunks, 1, n1)
×
793
    return B
×
794
end
795

796
prepend!(B::BitVector, items) = prepend!(B, BitArray(items))
6,264✔
797
prepend!(A::Vector{Bool}, items::BitVector) = prepend!(A, Array(items))
×
798

799
function sizehint!(B::BitVector, sz::Integer)
×
800
    sizehint!(B.chunks, num_bit_chunks(sz))
×
801
    return B
×
802
end
803

804
resize!(B::BitVector, n::Integer) = _resize_int!(B, Int(n))
114,962✔
805
function _resize_int!(B::BitVector, n::Int)
×
806
    n0 = length(B)
×
807
    n == n0 && return B
×
808
    n >= 0 || throw(BoundsError(B, n))
×
809
    if n < n0
×
810
        deleteat!(B, n+1:n0)
×
811
        return B
×
812
    end
813
    Bc = B.chunks
×
814
    k0 = length(Bc)
×
815
    k1 = num_bit_chunks(n)
×
816
    if k1 > k0
×
817
        _growend!(Bc, k1 - k0)
×
818
        Bc[end] = UInt64(0)
×
819
    end
820
    B.len = n
×
821
    return B
×
822
end
823

824
function pop!(B::BitVector)
×
825
    isempty(B) && throw(ArgumentError("argument must not be empty"))
×
826
    item = B[end]
×
827
    B[end] = false
×
828

829
    l = _mod64(length(B))
×
830
    l == 1 && _deleteend!(B.chunks, 1)
×
831
    B.len -= 1
×
832

833
    return item
×
834
end
835

836
function pushfirst!(B::BitVector, item)
780✔
837
    item = convert(Bool, item)
780✔
838

839
    Bc = B.chunks
780✔
840

841
    l = _mod64(length(B))
780✔
842
    if l == 0
780✔
843
        _growend!(Bc, 1)
15✔
844
        Bc[end] = UInt64(0)
15✔
845
    end
846
    B.len += 1
780✔
847
    if B.len == 1
780✔
848
        Bc[1] = item
3✔
849
        return B
3✔
850
    end
851
    for i = length(Bc) : -1 : 2
1,362✔
852
        Bc[i] = (Bc[i] << 1) | (Bc[i-1] >>> 63)
1,200✔
853
    end
1,812✔
854
    Bc[1] = UInt64(item) | (Bc[1] << 1)
777✔
855
    return B
777✔
856
end
857

858
function popfirst!(B::BitVector)
×
859
    isempty(B) && throw(ArgumentError("argument must not be empty"))
×
860
    @inbounds begin
×
861
        item = B[1]
×
862

863
        Bc = B.chunks
×
864

865
        for i = 1 : length(Bc) - 1
×
866
            Bc[i] = (Bc[i] >>> 1) | (Bc[i+1] << 63)
×
867
        end
×
868

869
        l = _mod64(length(B))
×
870
        if l == 1
×
871
            _deleteend!(Bc, 1)
×
872
        else
873
            Bc[end] >>>= 1
×
874
        end
875
        B.len -= 1
×
876
    end
877

878
    return item
×
879
end
880

881
insert!(B::BitVector, i::Integer, item) = _insert_int!(B, Int(i), item)
813✔
882
function _insert_int!(B::BitVector, i::Int, item)
813✔
883
    i = Int(i)
813✔
884
    n = length(B)
813✔
885
    1 <= i <= n+1 || throw(BoundsError(B, i))
819✔
886
    item = convert(Bool, item)
821✔
887

888
    Bc = B.chunks
807✔
889

890
    k, j = get_chunks_id(i)
807✔
891

892
    l = _mod64(length(B))
807✔
893
    if l == 0
807✔
894
        _growend!(Bc, 1)
15✔
895
        Bc[end] = UInt64(0)
15✔
896
    end
897
    B.len += 1
807✔
898

899
    for t = length(Bc) : -1 : k + 1
1,354✔
900
        Bc[t] = (Bc[t] << 1) | (Bc[t - 1] >>> 63)
789✔
901
    end
1,098✔
902

903
    msk_aft = (_msk64 << j)
807✔
904
    msk_bef = ~msk_aft
807✔
905
    Bc[k] = (msk_bef & Bc[k]) | ((msk_aft & Bc[k]) << 1)
807✔
906
    B[i] = item
807✔
907
    B
807✔
908
end
909

910
function _deleteat!(B::BitVector, i::Int)
×
911
    k, j = get_chunks_id(i)
×
912

913
    msk_bef = _msk64 >>> (63 - j)
×
914
    msk_aft = ~msk_bef
×
915
    msk_bef >>>= 1
×
916

917
    Bc = B.chunks
×
918

919
    @inbounds begin
×
920
        Bc[k] = (msk_bef & Bc[k]) | ((msk_aft & Bc[k]) >> 1)
×
921
        if length(Bc) > k
×
922
            Bc[k] |= (Bc[k + 1] << 63)
×
923
        end
924

925
        for t = k + 1 : length(Bc) - 1
×
926
            Bc[t] = (Bc[t] >>> 1) | (Bc[t + 1] << 63)
×
927
        end
×
928

929
        l = _mod64(length(B))
×
930

931
        if l == 1
×
932
            _deleteend!(Bc, 1)
×
933
        elseif length(Bc) > k
×
934
            Bc[end] >>>= 1
×
935
        end
936
    end
937

938
    B.len -= 1
×
939

940
    return B
×
941
end
942

943
function deleteat!(B::BitVector, i::Integer)
810✔
944
    i isa Bool && depwarn("passing Bool as an index is deprecated", :deleteat!)
810✔
945
    i = Int(i)
810✔
946
    n = length(B)
810✔
947
    1 <= i <= n || throw(BoundsError(B, i))
813✔
948

949
    return _deleteat!(B, i)
807✔
950
end
951

952
function deleteat!(B::BitVector, r::AbstractUnitRange{Int})
×
953
    n = length(B)
×
954
    i_f = first(r)
×
955
    i_l = last(r)
×
956
    1 <= i_f || throw(BoundsError(B, i_f))
×
957
    i_l <= n || throw(BoundsError(B, n+1))
×
958

959
    Bc = B.chunks
×
960
    new_l = length(B) - length(r)
×
961
    delta_k = num_bit_chunks(new_l) - length(Bc)
×
962

963
    copy_chunks!(Bc, i_f, Bc, i_l+1, n-i_l)
×
964

965
    delta_k < 0 && _deleteend!(Bc, -delta_k)
×
966

967
    B.len = new_l
×
968

969
    if new_l > 0
×
970
        Bc[end] &= _msk_end(new_l)
×
971
    end
972

973
    return B
×
974
end
975

976
function deleteat!(B::BitVector, inds)
101,049✔
977
    n = new_l = length(B)
101,049✔
978
    y = iterate(inds)
101,049✔
979
    y === nothing && return B
101,049✔
980

981
    Bc = B.chunks
100,651✔
982

983
    (p, s) = y
100,651✔
984
    checkbounds(B, p)
100,666✔
985
    p isa Bool && throw(ArgumentError("invalid index $p of type Bool"))
100,636✔
986
    q = p+1
100,633✔
987
    new_l -= 1
100,633✔
988
    y = iterate(inds, s)
100,633✔
989
    while y !== nothing
4,444,156✔
990
        (i, s) = y
4,343,538✔
991
        if !(q <= i <= n)
4,343,538✔
992
            i isa Bool && throw(ArgumentError("invalid index $i of type Bool"))
15✔
993
            i < q && throw(ArgumentError("indices must be unique and sorted"))
12✔
994
            throw(BoundsError(B, i))
6✔
995
        end
996
        new_l -= 1
4,343,523✔
997
        if i > q
4,343,523✔
998
            copy_chunks!(Bc, Int(p), Bc, Int(q), Int(i-q))
2,146,694✔
999
            p += i-q
2,146,694✔
1000
        end
1001
        q = i+1
4,343,523✔
1002
        y = iterate(inds, s)
4,343,523✔
1003
    end
4,343,523✔
1004

1005
    q <= n && copy_chunks!(Bc, Int(p), Bc, Int(q), Int(n-q+1))
100,621✔
1006

1007
    delta_k = num_bit_chunks(new_l) - length(Bc)
100,618✔
1008
    delta_k < 0 && _deleteend!(Bc, -delta_k)
124,598✔
1009

1010
    B.len = new_l
100,618✔
1011

1012
    if new_l > 0
100,618✔
1013
        Bc[end] &= _msk_end(new_l)
100,618✔
1014
    end
1015

1016
    return B
100,618✔
1017
end
1018

1019
function deleteat!(B::BitVector, inds::AbstractVector{Bool})
12,012✔
1020
    length(inds) == length(B) || throw(BoundsError(B, inds))
12,015✔
1021

1022
    n = new_l = length(B)
12,009✔
1023
    y = findfirst(inds)
29,220✔
1024
    y === nothing && return B
12,009✔
1025

1026
    Bc = B.chunks
11,427✔
1027

1028
    p = y
11,427✔
1029
    s = y + 1
11,427✔
1030
    checkbounds(B, p)
11,427✔
1031
    q = p + 1
11,427✔
1032
    new_l -= 1
11,427✔
1033
    y = findnext(inds, s)
27,012✔
1034
    while y !== nothing
63,381✔
1035
        i = y
51,954✔
1036
        s = y + 1
51,954✔
1037
        new_l -= 1
51,954✔
1038
        if i > q
51,954✔
1039
            copy_chunks!(Bc, Int(p), Bc, Int(q), Int(i-q))
23,178✔
1040
            p += i - q
23,178✔
1041
        end
1042
        q = i + 1
51,954✔
1043
        y = findnext(inds, s)
116,847✔
1044
    end
51,954✔
1045

1046
    q <= n && copy_chunks!(Bc, Int(p), Bc, Int(q), Int(n - q + 1))
11,427✔
1047

1048
    delta_k = num_bit_chunks(new_l) - length(Bc)
11,427✔
1049
    delta_k < 0 && _deleteend!(Bc, -delta_k)
11,427✔
1050

1051
    B.len = new_l
11,427✔
1052

1053
    if new_l > 0
11,427✔
1054
        Bc[end] &= _msk_end(new_l)
10,788✔
1055
    end
1056

1057
    return B
11,427✔
1058
end
1059

1060
keepat!(B::BitVector, inds) = _keepat!(B, inds)
6✔
1061
keepat!(B::BitVector, inds::AbstractVector{Bool}) = _keepat!(B, inds)
3✔
1062

1063
function splice!(B::BitVector, i::Integer)
807✔
1064
    # TODO: after deprecation remove the four lines below
1065
    #       as v = B[i] is enough to do both bounds checking
1066
    #       and Bool check then just pass Int(i) to _deleteat!
1067
    i isa Bool && depwarn("passing Bool as an index is deprecated", :splice!)
807✔
1068
    i = Int(i)
807✔
1069
    n = length(B)
807✔
1070
    1 <= i <= n || throw(BoundsError(B, i))
807✔
1071

1072
    v = B[i]   # TODO: change to a copy if/when subscripting becomes an ArrayView
807✔
1073
    _deleteat!(B, i)
807✔
1074
    return v
807✔
1075
end
1076

1077
const _default_bit_splice = BitVector()
1078

1079
function splice!(B::BitVector, r::Union{AbstractUnitRange{Int}, Integer}, ins::AbstractArray = _default_bit_splice)
186,462✔
1080
    r isa Bool && depwarn("passing Bool as an index is deprecated", :splice!)
325,908✔
1081
    _splice_int!(B, isa(r, AbstractUnitRange{Int}) ? r : Int(r), ins)
224,118✔
1082
end
1083

1084
function _splice_int!(B::BitVector, r, ins)
224,118✔
1085
    n = length(B)
224,118✔
1086
    i_f, i_l = first(r), last(r)
224,118✔
1087
    1 <= i_f <= n+1 || throw(BoundsError(B, i_f))
224,118✔
1088
    i_l <= n || throw(BoundsError(B, n+1))
224,118✔
1089

1090
    Bins = convert(BitArray, ins)
224,118✔
1091

1092
    if (i_f > n)
224,118✔
1093
        append!(B, Bins)
207✔
1094
        return BitVector()
108✔
1095
    end
1096

1097
    v = B[r]  # TODO: change to a copy if/when subscripting becomes an ArrayView
224,010✔
1098

1099
    Bc = B.chunks
224,010✔
1100

1101
    lins = length(Bins)
224,010✔
1102
    ldel = length(r)
224,010✔
1103

1104
    new_l = length(B) + lins - ldel
224,010✔
1105
    delta_k = num_bit_chunks(new_l) - length(Bc)
224,010✔
1106

1107
    delta_k > 0 && _growend!(Bc, delta_k)
224,010✔
1108

1109
    copy_chunks!(Bc, i_f+lins, Bc, i_l+1, n-i_l)
224,010✔
1110
    copy_chunks!(Bc, i_f, Bins.chunks, 1, lins)
224,010✔
1111

1112
    delta_k < 0 && _deleteend!(Bc, -delta_k)
340,971✔
1113

1114
    B.len = new_l
224,010✔
1115

1116
    if new_l > 0
224,010✔
1117
        Bc[end] &= _msk_end(new_l)
223,998✔
1118
    end
1119

1120
    return v
224,010✔
1121
end
1122

1123
function splice!(B::BitVector, r::Union{AbstractUnitRange{Int}, Integer}, ins)
37,656✔
1124
    Bins = BitVector(undef, length(ins))
37,656✔
1125
    i = 1
37,656✔
1126
    for x in ins
75,312✔
1127
        Bins[i] = Bool(x)
4,031,511✔
1128
        i += 1
4,031,511✔
1129
    end
8,063,022✔
1130
    return splice!(B, r, Bins)
37,656✔
1131
end
1132

1133

1134
function empty!(B::BitVector)
1135
    _deleteend!(B.chunks, length(B.chunks))
802,176✔
1136
    B.len = 0
12,534✔
1137
    return B
12,534✔
1138
end
1139

1140
## Unary operators ##
1141

1142
function (-)(B::BitArray)
6✔
1143
    A = zeros(Int, size(B))
1,023✔
1144
    l = length(B)
6✔
1145
    l == 0 && return A
6✔
1146
    Bc = B.chunks
3✔
1147
    ind = 1
3✔
1148
    for i = 1:length(Bc)-1
3✔
1149
        u = UInt64(1)
15✔
1150
        c = Bc[i]
15✔
1151
        for j = 1:64
15✔
1152
            if c & u != 0
960✔
1153
                A[ind] = -1
474✔
1154
            end
1155
            ind += 1
960✔
1156
            u <<= 1
960✔
1157
        end
1,905✔
1158
    end
27✔
1159
    u = UInt64(1)
3✔
1160
    c = Bc[end]
3✔
1161
    for j = 0:_mod64(l-1)
3✔
1162
        if c & u != 0
60✔
1163
            A[ind] = -1
35✔
1164
        end
1165
        ind += 1
60✔
1166
        u <<= 1
60✔
1167
    end
117✔
1168
    return A
3✔
1169
end
1170

1171
## Binary arithmetic operators ##
1172

1173
for f in (:+, :-)
1174
    @eval function ($f)(A::BitArray, B::BitArray)
195✔
1175
        r = Array{Int}(undef, promote_shape(size(A), size(B)))
195✔
1176
        ay, by = iterate(A), iterate(B)
390✔
1177
        ri = 1
195✔
1178
        # promote_shape guarantees that A and B have the
1179
        # same iteration space
1180
        while ay !== nothing
5,055✔
1181
            @inbounds r[ri] = ($f)(ay[1], by[1])
4,860✔
1182
            ri += 1
4,860✔
1183
            ay, by = iterate(A, ay[2]), iterate(B, by[2])
9,525✔
1184
        end
4,860✔
1185
        return r
195✔
1186
    end
1187
end
1188

1189
for f in (:/, :\)
1190
    @eval begin
1191
        ($f)(A::Union{BitMatrix,BitVector}, B::Union{BitMatrix,BitVector}) = ($f)(Array(A), Array(B))
×
1192
    end
1193
end
1194
(/)(B::BitArray, x::Number) = (/)(Array(B), x)
3✔
1195
(/)(x::Number, B::BitArray) = (/)(x, Array(B))
×
1196

1197
## promotion to complex ##
1198

1199
# TODO?
1200

1201
## comparison operators ##
1202

1203
function (==)(A::BitArray, B::BitArray)
12,078✔
1204
    size(A) != size(B) && return false
3,451,122✔
1205
    return A.chunks == B.chunks
1,725,564✔
1206
end
1207

1208

1209
## Data movement ##
1210

1211
# TODO some of this could be optimized
1212

1213
_reverse(A::BitArray, d::Tuple{Integer}) = _reverse(A, d[1])
×
1214
function _reverse(A::BitArray, d::Int)
15✔
1215
    nd = ndims(A)
15✔
1216
    1 ≤ d ≤ nd || throw(ArgumentError("dimension $d is not 1 ≤ $d ≤ $nd"))
18✔
1217
    sd = size(A, d)
12✔
1218
    sd == 1 && return copy(A)
12✔
1219

1220
    B = similar(A)
12✔
1221

1222
    nnd = 0
12✔
1223
    for i = 1:nd
12✔
1224
        nnd += size(A,i)==1 || i==d
96✔
1225
    end
84✔
1226
    if nnd == nd
12✔
1227
        # reverse along the only non-singleton dimension
1228
        for i = 1:sd
×
1229
            B[i] = A[sd+1-i]
×
1230
        end
×
1231
        return B
×
1232
    end
1233

1234
    d_in = size(A)
12✔
1235
    leading = d_in[1:(d-1)]
21✔
1236
    M = prod(leading)
21✔
1237
    N = length(A)
12✔
1238
    stride = M * sd
12✔
1239

1240
    if M == 1
12✔
1241
        for j = 0:stride:(N-stride)
3✔
1242
            for i = 1:sd
504✔
1243
                ri = sd+1-i
2,520✔
1244
                B[j + ri] = A[j + i]
2,520✔
1245
            end
4,536✔
1246
        end
504✔
1247
    else
1248
        for i = 1:sd
9✔
1249
            ri = sd+1-i
54✔
1250
            for j=0:stride:(N-stride)
54✔
1251
                offs = j + 1 + (i-1)*M
588✔
1252
                boffs = j + 1 + (ri-1)*M
588✔
1253
                copy_chunks!(B.chunks, boffs, A.chunks, offs, M)
588✔
1254
            end
588✔
1255
        end
54✔
1256
    end
1257
    return B
12✔
1258
end
1259

1260
function _reverse!(B::BitVector, ::Colon)
×
1261
    # Basic idea: each chunk is divided into two blocks of size k = n % 64, and
1262
    # h = 64 - k. Walk from either end (with indices i and j) reversing chunks
1263
    # and separately ORing their two blocks into place.
1264
    #
1265
    #           chunk 3                  chunk 2                  chunk 1
1266
    # ┌───────────────┬───────┐┌───────────────┬───────┐┌───────────────┬───────┐
1267
    # │000000000000000│   E   ││       D       │   C   ││       B       │   A   │
1268
    # └───────────────┴───────┘└───────────────┴───────┘└───────────────┴───────┘
1269
    #                     k            h           k            h            k
1270
    # yielding;
1271
    # ┌───────────────┬───────┐┌───────────────┬───────┐┌───────────────┬───────┐
1272
    # │000000000000000│  A'   ││      B'       │  C'   ││      D'       │  E'   │
1273
    # └───────────────┴───────┘└───────────────┴───────┘└───────────────┴───────┘
1274

1275
    n = length(B)
×
1276
    n == 0 && return B
×
1277

1278
    k = _mod64(n+63) + 1
×
1279
    h = 64 - k
×
1280

1281
    i, j = 0, length(B.chunks)
×
1282
    u = UInt64(0)
×
1283
    v = bitreverse(B.chunks[j])
×
1284
    B.chunks[j] = 0
×
1285
    @inbounds while true
×
1286
        i += 1
×
1287
        if i == j
×
1288
            break
×
1289
        end
1290
        u = bitreverse(B.chunks[i])
×
1291
        B.chunks[i] = 0
×
1292
        B.chunks[j] |= u >>> h
×
1293
        B.chunks[i] |= v >>> h
×
1294

1295
        j -= 1
×
1296
        if i == j
×
1297
            break
×
1298
        end
1299
        v = bitreverse(B.chunks[j])
×
1300
        B.chunks[j] = 0
×
1301
        B.chunks[i] |= v << k
×
1302
        B.chunks[j] |= u << k
×
1303
    end
×
1304

1305
    if isodd(length(B.chunks))
×
1306
        B.chunks[i] |= v >>> h
×
1307
    else
1308
        B.chunks[i] |= u << k
×
1309
    end
1310

1311
    return B
×
1312
end
1313

1314
function (<<)(B::BitVector, i::UInt)
×
1315
    n = length(B)
×
1316
    i == 0 && return copy(B)
×
1317
    A = falses(n)
×
1318
    i < n && copy_chunks!(A.chunks, 1, B.chunks, Int(i+1), Int(n-i))
×
1319
    return A
×
1320
end
1321

1322
function (>>>)(B::BitVector, i::UInt)
×
1323
    n = length(B)
×
1324
    i == 0 && return copy(B)
×
1325
    A = falses(n)
×
1326
    i < n && copy_chunks!(A.chunks, Int(i+1), B.chunks, 1, Int(n-i))
×
1327
    return A
×
1328
end
1329

1330
"""
1331
    >>(B::BitVector, n)::BitVector
1332

1333
Right bit shift operator, `B >> n`. For `n >= 0`, the result is `B`
1334
with elements shifted `n` positions forward, filling with `false`
1335
values. If `n < 0`, elements are shifted backwards. Equivalent to
1336
`B << -n`.
1337

1338
# Examples
1339
```jldoctest
1340
julia> B = BitVector([true, false, true, false, false])
1341
5-element BitVector:
1342
 1
1343
 0
1344
 1
1345
 0
1346
 0
1347

1348
julia> B >> 1
1349
5-element BitVector:
1350
 0
1351
 1
1352
 0
1353
 1
1354
 0
1355

1356
julia> B >> -1
1357
5-element BitVector:
1358
 0
1359
 1
1360
 0
1361
 0
1362
 0
1363
```
1364
"""
1365
(>>)(B::BitVector, i::Union{Int, UInt}) = B >>> i
×
1366

1367
# signed integer version of shift operators with handling of negative values
1368
"""
1369
    <<(B::BitVector, n)::BitVector
1370

1371
Left bit shift operator, `B << n`. For `n >= 0`, the result is `B`
1372
with elements shifted `n` positions backwards, filling with `false`
1373
values. If `n < 0`, elements are shifted forwards. Equivalent to
1374
`B >> -n`.
1375

1376
# Examples
1377
```jldoctest
1378
julia> B = BitVector([true, false, true, false, false])
1379
5-element BitVector:
1380
 1
1381
 0
1382
 1
1383
 0
1384
 0
1385

1386
julia> B << 1
1387
5-element BitVector:
1388
 0
1389
 1
1390
 0
1391
 0
1392
 0
1393

1394
julia> B << -1
1395
5-element BitVector:
1396
 0
1397
 1
1398
 0
1399
 1
1400
 0
1401
```
1402
"""
1403
(<<)(B::BitVector, i::Int) = (i >=0 ? B << unsigned(i) : B >> unsigned(-i))
×
1404

1405
"""
1406
    >>>(B::BitVector, n)::BitVector
1407

1408
Unsigned right bitshift operator, `B >>> n`. Equivalent to `B >> n`. See [`>>`](@ref) for
1409
details and examples.
1410
"""
1411
(>>>)(B::BitVector, i::Int) = (i >=0 ? B >> unsigned(i) : B << unsigned(-i))
×
1412

1413
circshift!(dest::BitVector, src::BitVector, i::Integer) = _circshift_int!(dest, src, Int(i))
96✔
1414
function _circshift_int!(dest::BitVector, src::BitVector, i::Int)
×
1415
    i = Int(i)
×
1416
    length(dest) == length(src) || throw(ArgumentError("destination and source should be of same size"))
×
1417
    n = length(dest)
×
1418
    i %= n
×
1419
    i == 0 && return (src === dest ? src : copyto!(dest, src))
×
1420
    Bc = (src === dest ? copy(src.chunks) : src.chunks)
×
1421
    if i > 0 # right
×
1422
        copy_chunks!(dest.chunks, i+1, Bc, 1, n-i)
×
1423
        copy_chunks!(dest.chunks, 1, Bc, n-i+1, i)
×
1424
    else # left
1425
        i = -i
×
1426
        copy_chunks!(dest.chunks, 1, Bc, i+1, n-i)
×
1427
        copy_chunks!(dest.chunks, n-i+1, Bc, 1, i)
×
1428
    end
1429
    return dest
×
1430
end
1431

1432
circshift!(B::BitVector, i::Integer) = circshift!(B, B, i)
48✔
1433

1434
## count & find ##
1435

1436
function bitcount(Bc::Vector{UInt64}; init::T=0) where {T}
937,728✔
1437
    n::T = init
664,507✔
1438
    @inbounds for i = 1:length(Bc)
1,005,136✔
1439
        n = (n + count_ones(Bc[i])) % T
636,307✔
1440
    end
780,176✔
1441
    return n
669,115✔
1442
end
1443

1444
_count(::typeof(identity), B::BitArray, ::Colon, init) = bitcount(B.chunks; init)
409,454✔
1445

1446
function unsafe_bitfindnext(Bc::Vector{UInt64}, start::Int)
1447
    chunk_start = _div64(start-1)+1
1,140,863✔
1448
    within_chunk_start = _mod64(start-1)
1,140,863✔
1449
    mask = _msk64 << within_chunk_start
1,140,863✔
1450

1451
    @inbounds begin
970,265✔
1452
        if Bc[chunk_start] & mask != 0
1,141,079✔
1453
            return (chunk_start-1) << 6 + trailing_zeros(Bc[chunk_start] & mask) + 1
656,276✔
1454
        end
1455

1456
        for i = chunk_start+1:length(Bc)
490,197✔
1457
            if Bc[i] != 0
228,768✔
1458
                return (i-1) << 6 + trailing_zeros(Bc[i]) + 1
131,988✔
1459
            end
1460
        end
191,175✔
1461
    end
1462
    return nothing
352,815✔
1463
end
1464

1465
# returns the index of the next true element, or nothing if all false
1466
function findnext(B::BitArray, start::Integer)
137,235✔
1467
    start = Int(start)
184,117✔
1468
    start > 0 || throw(BoundsError(B, start))
184,111✔
1469
    start > length(B) && return nothing
184,099✔
1470
    unsafe_bitfindnext(B.chunks, start)
181,060✔
1471
end
1472

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

1475
# aux function: same as findnext(~B, start), but performed without temporaries
1476
function findnextnot(B::BitArray, start::Int)
167,709✔
1477
    start > 0 || throw(BoundsError(B, start))
167,715✔
1478
    start > length(B) && return nothing
167,703✔
1479

1480
    Bc = B.chunks
167,679✔
1481
    l = length(Bc)
167,679✔
1482
    l == 0 && return nothing
167,679✔
1483

1484
    chunk_start = _div64(start-1)+1
167,679✔
1485
    within_chunk_start = _mod64(start-1)
167,679✔
1486
    mask = ~(_msk64 << within_chunk_start)
167,679✔
1487

1488
    @inbounds if chunk_start < l
167,679✔
1489
        if Bc[chunk_start] | mask != _msk64
166,401✔
1490
            return (chunk_start-1) << 6 + trailing_ones(Bc[chunk_start] | mask) + 1
75,825✔
1491
        end
1492
        for i = chunk_start+1:l-1
92,115✔
1493
            if Bc[i] != _msk64
140,991✔
1494
                return (i-1) << 6 + trailing_ones(Bc[i]) + 1
85,935✔
1495
            end
1496
        end
107,010✔
1497
        if Bc[l] != _msk_end(B)
4,641✔
1498
            return (l-1) << 6 + trailing_ones(Bc[l]) + 1
3,459✔
1499
        end
1500
    elseif Bc[l] | mask != _msk_end(B)
1,278✔
1501
        return (l-1) << 6 + trailing_ones(Bc[l] | mask) + 1
881✔
1502
    end
1503
    return nothing
1,579✔
1504
end
1505
findfirstnot(B::BitArray) = findnextnot(B,1)
783✔
1506

1507
# returns the index of the first matching element
1508
function findnext(pred::Fix2{<:Union{typeof(isequal),typeof(==)},Bool},
24✔
1509
                  B::BitArray, start::Integer)
1510
    v = pred.x
24✔
1511
    v == false && return findnextnot(B, Int(start))
24✔
1512
    v == true && return findnext(B, start)
12✔
1513
    return nothing
×
1514
end
1515
#findfirst(B::BitArray, v) = findnext(B, 1, v)  ## defined in array.jl
1516

1517
# returns the index of the first element for which the function returns true
1518
findnext(testf::Function, B::BitArray, start::Integer) = _findnext_int(testf, B, Int(start))
41,481✔
1519
function _findnext_int(testf::Function, B::BitArray, start::Int)
41,481✔
1520
    f0::Bool = testf(false)
41,481✔
1521
    f1::Bool = testf(true)
41,481✔
1522
    !f0 && f1 && return findnext(B, start)
41,481✔
1523
    f0 && !f1 && return findnextnot(B, start)
36,777✔
1524

1525
    start > 0 || throw(BoundsError(B, start))
7,092✔
1526
    start > length(B) && return nothing
7,068✔
1527
    f0 && f1 && return start
7,026✔
1528
    return nothing # last case: !f0 && !f1
4,683✔
1529
end
1530
#findfirst(testf::Function, B::BitArray) = findnext(testf, B, 1)  ## defined in array.jl
1531

1532
function unsafe_bitfindprev(Bc::Vector{UInt64}, start::Int)
954✔
1533
    chunk_start = _div64(start-1)+1
954✔
1534
    mask = _msk_end(start)
954✔
1535

1536
    @inbounds begin
954✔
1537
        if Bc[chunk_start] & mask != 0
954✔
1538
            return (chunk_start-1) << 6 + (top_set_bit(Bc[chunk_start] & mask))
954✔
1539
        end
1540

1541
        for i = (chunk_start-1):-1:1
×
1542
            if Bc[i] != 0
×
1543
                return (i-1) << 6 + (top_set_bit(Bc[i]))
×
1544
            end
1545
        end
×
1546
    end
1547
    return nothing
×
1548
end
1549

1550
# returns the index of the previous true element, or nothing if all false
1551
function findprev(B::BitArray, start::Integer)
37,899✔
1552
    start = Int(start)
41,102✔
1553
    start > 0 || return nothing
41,096✔
1554
    start > length(B) && throw(BoundsError(B, start))
41,084✔
1555
    unsafe_bitfindprev(B.chunks, start)
41,078✔
1556
end
1557

1558
function findprevnot(B::BitArray, start::Int)
65,038✔
1559
    start = Int(start)
65,038✔
1560
    start > 0 || return nothing
65,044✔
1561
    start > length(B) && throw(BoundsError(B, start))
65,032✔
1562

1563
    Bc = B.chunks
65,026✔
1564

1565
    chunk_start = _div64(start-1)+1
65,026✔
1566
    mask = ~_msk_end(start)
65,026✔
1567

1568
    @inbounds begin
65,026✔
1569
        if Bc[chunk_start] | mask != _msk64
65,026✔
1570
            return (chunk_start-1) << 6 + (64 - leading_ones(Bc[chunk_start] | mask))
52,355✔
1571
        end
1572

1573
        for i = chunk_start-1:-1:1
25,312✔
1574
            if Bc[i] != _msk64
13,233✔
1575
                return (i-1) << 6 + (64 - leading_ones(Bc[i]))
12,631✔
1576
            end
1577
        end
1,185✔
1578
    end
1579
    return nothing
40✔
1580
end
1581
findlastnot(B::BitArray) = findprevnot(B, length(B))
3✔
1582

1583
# returns the index of the previous matching element
1584
function findprev(pred::Fix2{<:Union{typeof(isequal),typeof(==)},Bool},
804✔
1585
                  B::BitArray, start::Integer)
1586
    v = pred.x
804✔
1587
    v == false && return findprevnot(B, Int(start))
804✔
1588
    v == true && return findprev(B, start)
792✔
1589
    return nothing
×
1590
end
1591
#findlast(B::BitArray, v) = findprev(B, 1, v)  ## defined in array.jl
1592

1593
# returns the index of the previous element for which the function returns true
1594
findprev(testf::Function, B::BitArray, start::Integer) = _findprev_int(testf, B, Int(start))
29,311✔
1595
function _findprev_int(testf::Function, B::BitArray, start::Int)
26,598✔
1596
    f0::Bool = testf(false)
29,311✔
1597
    f1::Bool = testf(true)
29,311✔
1598
    !f0 && f1 && return findprev(B, start)
29,311✔
1599
    f0 && !f1 && return findprevnot(B, start)
27,169✔
1600

1601
    start > 0 || return nothing
48✔
1602
    start > length(B) && throw(BoundsError(B, start))
18✔
1603
    f0 && f1 && return start
6✔
1604
    return nothing # last case: !f0 && !f1
3✔
1605
end
1606
#findlast(testf::Function, B::BitArray) = findprev(testf, B, 1)  ## defined in array.jl
1607

1608
function findmax(a::BitArray)
9✔
1609
    isempty(a) && throw(ArgumentError("BitArray must be non-empty"))
24✔
1610
    m, mi = false, 1
21✔
1611
    ti = 1
21✔
1612
    ac = a.chunks
21✔
1613
    for i = 1:length(ac)
21✔
1614
        @inbounds k = trailing_zeros(ac[i])
33✔
1615
        ti += k
33✔
1616
        k == 64 || return (true, @inbounds keys(a)[ti])
51✔
1617
    end
27✔
1618
    return m, @inbounds keys(a)[mi]
3✔
1619
end
1620

1621
function findmin(a::BitArray)
9✔
1622
    isempty(a) && throw(ArgumentError("BitArray must be non-empty"))
24✔
1623
    m, mi = true, 1
21✔
1624
    ti = 1
21✔
1625
    ac = a.chunks
21✔
1626
    for i = 1:length(ac)-1
21✔
1627
        @inbounds k = trailing_ones(ac[i])
18✔
1628
        ti += k
18✔
1629
        k == 64 || return (false, @inbounds keys(a)[ti])
24✔
1630
    end
21✔
1631
    l = Base._mod64(length(a)-1) + 1
15✔
1632
    @inbounds k = trailing_ones(ac[end] & Base._msk_end(l))
15✔
1633
    ti += k
15✔
1634
    k == l || return (false, @inbounds keys(a)[ti])
27✔
1635
    return (m, @inbounds keys(a)[mi])
3✔
1636
end
1637

1638
# findall helper functions
1639
# Generic case (>2 dimensions)
1640
function allindices!(I, B::BitArray)
1641
    ind = first(keys(B))
22✔
1642
    for k = 1:length(B)
22✔
1643
        I[k] = ind
1,516✔
1644
        ind = nextind(B, ind)
2,272✔
1645
    end
3,010✔
1646
end
1647

1648
# Optimized case for vector
1649
function allindices!(I, B::BitVector)
×
1650
    I[:] .= 1:length(B)
×
1651
end
1652

1653
# Optimized case for matrix
1654
function allindices!(I, B::BitMatrix)
1655
    k = 1
3✔
1656
    for c = 1:size(B,2), r = 1:size(B,1)
3✔
1657
        I[k] = CartesianIndex(r, c)
12✔
1658
        k += 1
12✔
1659
    end
15✔
1660
end
1661

1662
@inline _overflowind(i1, irest::Tuple{}, size) = (i1, irest)
18,040✔
1663
@inline function _overflowind(i1, irest, size)
1664
    i2 = irest[1]
12,017✔
1665
    while i1 > size[1]
18,315✔
1666
        i1 -= size[1]
6,298✔
1667
        i2 += 1
6,298✔
1668
    end
6,298✔
1669
    i2, irest = _overflowind(i2, tail(irest), tail(size))
12,017✔
1670
    return (i1, (i2, irest...))
12,017✔
1671
end
1672

1673
@inline _toind(i1, irest::Tuple{}) = i1
230✔
1674
@inline _toind(i1, irest) = CartesianIndex(i1, irest...)
4,176✔
1675

1676
function findall(B::BitArray)
489✔
1677
    nnzB = count(B)
621✔
1678
    I = Vector{eltype(keys(B))}(undef, nnzB)
489✔
1679
    nnzB == 0 && return I
489✔
1680
    nnzB == length(B) && (allindices!(I, B); return I)
224✔
1681
    Bc = B.chunks
199✔
1682
    Bs = size(B)
199✔
1683
    Bi = i1 = i = 1
199✔
1684
    irest = ntuple(one, ndims(B) - 1)
199✔
1685
    c = Bc[1]
199✔
1686
    @inbounds while true
199✔
1687
        while c == 0
4,605✔
1688
            Bi == length(Bc) && return I
298✔
1689
            i1 += 64
99✔
1690
            Bi += 1
99✔
1691
            c = Bc[Bi]
99✔
1692
        end
99✔
1693

1694
        tz = trailing_zeros(c)
4,406✔
1695
        c = _blsr(c)
4,406✔
1696

1697
        i1, irest = _overflowind(i1 + tz, irest, Bs)
4,406✔
1698
        I[i] = _toind(i1, irest)
4,406✔
1699
        i += 1
4,406✔
1700
        i1 -= tz
4,406✔
1701
    end
4,406✔
1702
end
1703

1704
# For performance
1705
findall(::typeof(!iszero), B::BitArray) = findall(B)
3✔
1706

1707
## Reductions ##
1708

1709
_sum(A::BitArray, dims)    = reduce(+, A, dims=dims)
×
1710
_sum(B::BitArray, ::Colon) = count(B)
×
1711

1712
function all(B::BitArray)
3,181✔
1713
    isempty(B) && return true
10,454✔
1714
    Bc = B.chunks
10,448✔
1715
    @inbounds begin
10,448✔
1716
        for i = 1:length(Bc)-1
10,451✔
1717
            Bc[i] == _msk64 || return false
8,099✔
1718
        end
14,357✔
1719
        Bc[end] == _msk_end(B) || return false
10,958✔
1720
    end
1721
    return true
9,514✔
1722
end
1723

1724
function any(B::BitArray)
4,645✔
1725
    isempty(B) && return false
281,369✔
1726
    Bc = B.chunks
281,366✔
1727
    @inbounds begin
110,041✔
1728
        for i = 1:length(Bc)
386,775✔
1729
            Bc[i] == 0 || return true
566,358✔
1730
        end
151,888✔
1731
    end
1732
    return false
48,212✔
1733
end
1734

1735
minimum(B::BitArray) = isempty(B) ? throw(ArgumentError("argument must be non-empty")) : all(B)
6✔
1736
maximum(B::BitArray) = isempty(B) ? throw(ArgumentError("argument must be non-empty")) : any(B)
6✔
1737

1738
## map over bitarrays ##
1739

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

1744
map(::Union{typeof(~), typeof(!)}, A::BitArray) = bit_map!(~, similar(A), A)
1,140✔
1745
map(::typeof(zero), A::BitArray) = fill!(similar(A), false)
42✔
1746
map(::typeof(one), A::BitArray) = fill!(similar(A), true)
42✔
1747
map(::typeof(identity), A::BitArray) = copy(A)
42✔
1748

1749
map!(::Union{typeof(~), typeof(!)}, dest::BitArray, A::BitArray) = bit_map!(~, dest, A)
1,179✔
1750
map!(::typeof(zero), dest::BitArray, A::BitArray) = fill!(dest, false)
42✔
1751
map!(::typeof(one), dest::BitArray, A::BitArray) = fill!(dest, true)
42✔
1752
map!(::typeof(identity), dest::BitArray, A::BitArray) = copyto!(dest, A)
42✔
1753

1754
for (T, f) in ((:(Union{typeof(&), typeof(*), typeof(min)}), :(&)),
1755
               (:(Union{typeof(|), typeof(max)}),            :(|)),
1756
               (:(Union{typeof(xor), typeof(!=)}),           :xor),
1757
               (:(typeof(nand)),                             :nand),
1758
               (:(typeof(nor)),                              :nor),
1759
               (:(Union{typeof(>=), typeof(^)}),             :((p, q) -> p | ~q)),
3,912✔
1760
               (:(typeof(<=)),                               :((p, q) -> ~p | q)),
1,956✔
1761
               (:(typeof(==)),                               :((p, q) -> ~xor(p, q))),
1,956✔
1762
               (:(typeof(<)),                                :((p, q) -> ~p & q)),
1,956✔
1763
               (:(typeof(>)),                                :((p, q) -> p & ~q)))
1,956✔
1764
    @eval map(::$T, A::BitArray, B::BitArray) = bit_map!($f, similar(A), A, B)
3,909✔
1765
    @eval map!(::$T, dest::BitArray, A::BitArray, B::BitArray) = bit_map!($f, dest, A, B)
3,828✔
1766
end
1767

1768
# If we were able to specialize the function to a known bitwise operation,
1769
# map across the chunks. Otherwise, fall-back to the AbstractArray method that
1770
# iterates bit-by-bit.
1771
function bit_map!(f::F, dest::BitArray, A::BitArray) where F
1772
    length(A) <= length(dest) || throw(DimensionMismatch("length of destination must be >= length of collection"))
2,319✔
1773
    isempty(A) && return dest
2,319✔
1774
    destc = dest.chunks
2,154✔
1775
    Ac = A.chunks
2,154✔
1776
    len_Ac = length(Ac)
2,154✔
1777
    for i = 1:(len_Ac-1)
2,154✔
1778
        destc[i] = f(Ac[i])
51,645✔
1779
    end
101,640✔
1780
    # the last effected UInt64's original content
1781
    dest_last = destc[len_Ac]
2,154✔
1782
    _msk = _msk_end(A)
2,154✔
1783
    # first zero out the bits mask is going to change
1784
    # then update bits by `or`ing with a masked RHS
1785
    # DO NOT SEPARATE ONTO TO LINES.
1786
    # Otherwise there will be bugs when Ac aliases destc
1787
    destc[len_Ac] = (dest_last & (~_msk)) | f(Ac[len_Ac]) & _msk
2,154✔
1788
    dest
2,154✔
1789
end
1790
function bit_map!(f::F, dest::BitArray, A::BitArray, B::BitArray) where F
7,737✔
1791
    min_bitlen = min(length(A), length(B))
7,737✔
1792
    min_bitlen <= length(dest) || throw(DimensionMismatch("length of destination must be >= length of smallest input collection"))
7,737✔
1793
    isempty(A) && return dest
7,737✔
1794
    isempty(B) && return dest
7,185✔
1795
    destc = dest.chunks
7,185✔
1796
    Ac = A.chunks
7,185✔
1797
    Bc = B.chunks
7,185✔
1798
    len_Ac = min(length(Ac), length(Bc))
7,185✔
1799
    for i = 1:len_Ac-1
7,185✔
1800
        destc[i] = f(Ac[i], Bc[i])
172,776✔
1801
    end
340,032✔
1802
    # the last effected UInt64's original content
1803
    dest_last = destc[len_Ac]
7,185✔
1804
    _msk = _msk_end(min_bitlen)
7,185✔
1805
    # first zero out the bits mask is going to change
1806
    # then update bits by `or`ing with a masked RHS
1807
    # DO NOT SEPARATE ONTO TO LINES.
1808
    # Otherwise there will be bugs when Ac or Bc aliases destc
1809
    destc[len_Ac] = (dest_last & ~(_msk)) | f(Ac[end], Bc[end]) & _msk
7,185✔
1810
    dest
7,185✔
1811
end
1812

1813
## Filter ##
1814

1815
function filter(f, Bs::BitArray)
×
1816
    boolmap::Array{Bool} = map(f, Bs)
×
1817
    Bs[boolmap]
×
1818
end
1819

1820

1821
## Concatenation ##
1822

1823
function hcat(B::BitVector...)
12✔
1824
    height = length(B[1])
12✔
1825
    for j = 2:length(B)
12✔
1826
        length(B[j]) == height ||
15✔
1827
            throw(DimensionMismatch("dimensions must match: $j-th argument has length $(length(B[j])), should have $height"))
1828
    end
9✔
1829
    M = BitMatrix(undef, height, length(B))
9✔
1830
    for j = 1:length(B)
9✔
1831
        copy_chunks!(M.chunks, (height*(j-1))+1, B[j].chunks, 1, height)
18✔
1832
    end
27✔
1833
    return M
9✔
1834
end
1835

1836
function vcat(V::BitVector...)
1,270✔
1837
    n = 0
1,270✔
1838
    for Vk in V
1,270✔
1839
        n += length(Vk)
4,208✔
1840
    end
5,467✔
1841
    B = BitVector(undef, n)
1,270✔
1842
    j = 1
1,270✔
1843
    for Vk in V
1,270✔
1844
        copy_chunks!(B.chunks, j, Vk.chunks, 1, length(Vk))
4,208✔
1845
        j += length(Vk)
4,208✔
1846
    end
5,467✔
1847
    return B
1,270✔
1848
end
1849

1850
function hcat(A::Union{BitMatrix,BitVector}...)
6✔
1851
    nargs = length(A)
6✔
1852
    nrows = size(A[1], 1)
6✔
1853
    ncols = 0
6✔
1854
    dense = true
6✔
1855
    for j = 1:nargs
6✔
1856
        Aj = A[j]
15✔
1857
        nd = ndims(Aj)
21✔
1858
        ncols += (nd==2 ? size(Aj,2) : 1)
15✔
1859
        size(Aj, 1) == nrows ||
18✔
1860
            throw(DimensionMismatch("row lengths must match: $j-th element has first dim $(size(Aj, 1)), should have $nrows"))
1861
    end
21✔
1862

1863
    B = BitMatrix(undef, nrows, ncols)
3✔
1864

1865
    pos = 1
3✔
1866
    for k = 1:nargs
3✔
1867
        Ak = A[k]
9✔
1868
        n = length(Ak)
12✔
1869
        copy_chunks!(B.chunks, pos, Ak.chunks, 1, n)
12✔
1870
        pos += n
9✔
1871
    end
15✔
1872
    return B
3✔
1873
end
1874

1875
function vcat(A::BitMatrix...)
6✔
1876
    nargs = length(A)
6✔
1877
    nrows, nrowsA = 0, sizehint!(Int[], nargs)
6✔
1878
    for a in A
6✔
1879
        sz1 = size(a, 1)
18✔
1880
        nrows += sz1
18✔
1881
        push!(nrowsA, sz1)
18✔
1882
    end
24✔
1883
    ncols = size(A[1], 2)
6✔
1884
    for j = 2:nargs
6✔
1885
        size(A[j], 2) == ncols ||
15✔
1886
        throw(DimensionMismatch("column lengths must match: $j-th element has second dim $(size(A[j], 2)), should have $ncols"))
1887
    end
15✔
1888
    B = BitMatrix(undef, nrows, ncols)
3✔
1889
    Bc = B.chunks
3✔
1890
    pos_d = 1
3✔
1891
    pos_s = fill(1, nargs)
9✔
1892
    for j = 1:ncols, k = 1:nargs
3✔
1893
        copy_chunks!(Bc, pos_d, A[k].chunks, pos_s[k], nrowsA[k])
180✔
1894
        pos_s[k] += nrowsA[k]
180✔
1895
        pos_d += nrowsA[k]
180✔
1896
    end
237✔
1897
    return B
3✔
1898
end
1899

1900
# general case, specialized for BitArrays and Integers
1901
_cat(dims::Integer, X::Union{BitArray, Bool}...) = _cat(Int(dims)::Int, X...)
×
1902
function _cat(dims::Int, X::Union{BitArray, Bool}...)
12✔
1903
    dims = Int(dims)
12✔
1904
    catdims = dims2cat(dims)
24✔
1905
    shape = cat_shape(catdims, map(cat_size, X))
12✔
1906
    A = falses(shape)
12✔
1907
    return __cat(A, shape, catdims, X...)
12✔
1908
end
1909

1910
# hvcat -> use fallbacks in abstractarray.jl
1911

1912

1913
# BitArray I/O
1914

1915
write(s::IO, B::BitArray) = write(s, B.chunks)
8✔
1916
function read!(s::IO, B::BitArray)
1917
    n = length(B)
21✔
1918
    Bc = B.chunks
21✔
1919
    nc = length(read!(s, Bc))
21✔
1920
    if length(Bc) > 0 && Bc[end] & _msk_end(n) ≠ Bc[end]
15✔
1921
        Bc[end] &= _msk_end(n) # ensure that the BitArray is not broken
6✔
1922
        throw(DimensionMismatch("read mismatch, found non-zero bits after BitArray length"))
6✔
1923
    end
1924
    return B
9✔
1925
end
1926

1927
sizeof(B::BitArray) = sizeof(B.chunks)
6✔
1928

1929
function _split_rest(a::Union{Vector, BitVector}, n::Int)
1930
    _check_length_split_rest(length(a), n)
24✔
1931
    last_n = a[end-n+1:end]
42✔
1932
    resize!(a, length(a) - n)
21✔
1933
    return a, last_n
21✔
1934
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

© 2026 Coveralls, Inc