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

JuliaLang / julia / 1572

01 Feb 2026 09:55PM UTC coverage: 76.677% (-0.07%) from 76.749%
1572

push

buildkite

web-flow
docs: clarify 'using A, B' semantics (#60856)

Resolves #36090

62889 of 82018 relevant lines covered (76.68%)

23269256.38 hits per line

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

75.56
/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
135,204✔
30
        i = 1
135,204✔
31
        for d in dims
767,677✔
32
            d >= 0 || throw(ArgumentError("dimension size must be ≥ 0, got $d for dimension $i"))
2,407,317✔
33
            n *= d
2,407,317✔
34
            i += 1
300,068✔
35
        end
852,633✔
36
        nc = num_bit_chunks(n)
2,323,529✔
37
        chunks = Vector{UInt64}(undef, nc)
2,324,061✔
38
        nc > 0 && (chunks[end] = UInt64(0))
2,323,583✔
39
        b = new(chunks, n)
2,324,061✔
40
        N != 1 && (b.dims = dims)
216,334✔
41
        return b
605,551✔
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,839,733✔
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)
478✔
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
342,724,989✔
104
size(B::BitVector) = (B.len,)
233,762,222✔
105
size(B::BitArray) = B.dims
91,294,933✔
106

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

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

111
## aux functions ##
112

113
const _msk64 = ~UInt64(0)
114
@inline _div64(l) = l >> 6
966,040,778✔
115
@inline _mod64(l) = l & 63
962,516,803✔
116
@inline _blsr(x)= x & (x-1) #zeros the last set bit. Has native instruction on many archs. needed in multidimensional.jl
6,094,639✔
117
@inline _msk_end(l::Int) = _msk64 >>> _mod64(-l)
2,010,162✔
118
@inline _msk_end(B::BitArray) = _msk_end(length(B))
665,658✔
119
num_bit_chunks(n::Int) = _div64(n+63)
3,614,404✔
120

121
@inline get_chunks_id(i::Int) = _div64(i-1)+1, _mod64(i-1)
707,074,426✔
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
×
149
    msk_d0 = ~(u << ld0)
×
150
    msk_d1 = (u << (ld1+1))
×
151
    if delta_kd == 0
×
152
        msk_d0 |= msk_d1
×
153
    end
154
    msk_s0 = (u << ls0)
×
155
    if delta_ks == 0
×
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

207
        msk_d0 = ~(u << ld0)
×
208
        msk_d1 = (u << (ld1+1))
×
209
        if delta_kd == 0
×
210
            msk_d0 |= msk_d1
×
211
        end
212
        msk_s0 = (u << ls0)
×
213
        if delta_ks == 0
×
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)
45✔
235
    numbits <= 0 && return
45✔
236
    k0, l0 = get_chunks_id(pos)
45✔
237
    k1, l1 = get_chunks_id(pos+numbits-1)
45✔
238

239
    u = _msk64
45✔
240
    msk0 = (u << l0)
45✔
241
    msk1 = ~(u << (l1+1))
45✔
242
    if k1 == k0
45✔
243
        msk0 &= msk1
45✔
244
    end
245
    @inbounds if x
45✔
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
33✔
253
        for k = k0+1:k1-1
33✔
254
            Bc[k] = 0
×
255
        end
×
256
        k1 > k0 && (Bc[k1] &= ~msk1)
78✔
257
    end
258
end
259

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

263
# pack 8 Bools encoded as one contiguous UInt64 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}) =
276,939✔
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
242,966,209✔
353
    (B.chunks[_div64(i)+1] & (UInt64(1)<<_mod64(i)) != 0, i+1)
241,389,499✔
354
end
355

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

358
similar(B::BitArray) = BitArray(undef, size(B))
445,997✔
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)
289,085✔
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)
122,108✔
368
    y = convert(Bool, x)
122,108✔
369
    isempty(B) && return B
122,108✔
370
    Bc = B.chunks
122,106✔
371
    if !y
122,106✔
372
        fill!(Bc, 0)
122,461✔
373
    else
374
        fill!(Bc, _msk64)
980✔
375
        Bc[end] &= _msk_end(B)
565✔
376
    end
377
    return B
122,106✔
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,942✔
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,900✔
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,948✔
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,984✔
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))
183,529✔
450
    return dest
183,529✔
451
end
452

453
copyto!(dest::BitArray, doffs::Integer, src::Union{BitArray,Array}, soffs::Integer, n::Integer) =
423,538✔
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)
423,538✔
456
    n == 0 && return dest
423,538✔
457
    n < 0 && throw(ArgumentError("Number of elements to copy must be non-negative."))
423,148✔
458
    soffs < 1 && throw(BoundsError(src, soffs))
423,145✔
459
    doffs < 1 && throw(BoundsError(dest, doffs))
423,142✔
460
    soffs+n-1 > length(src) && throw(BoundsError(src, length(src)+1))
423,133✔
461
    doffs+n-1 > length(dest) && throw(BoundsError(dest, length(dest)+1))
248,023✔
462
    return unsafe_copyto!(dest, doffs, src, soffs, n)
183,517✔
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))
801,991✔
489
    Bc = B.chunks
801,991✔
490
    @inbounds for i = 1:length(A)
801,991✔
491
        A[i] = unsafe_bitgetindex(Bc, i)
290,682,905✔
492
    end
580,569,564✔
493
    return A
560,917✔
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,394✔
500
    _checkaxs(axes(B), axes(A))
62,394✔
501
    _copyto_bitarray!(B, A)
62,388✔
502
    return B::BitArray{N}
56,106✔
503
end
504

505
function _copyto_bitarray!(B::BitArray, A::AbstractArray)
75,694✔
506
    l = length(A)
75,703✔
507
    l == 0 && return B
75,703✔
508
    l > length(B) && throw(BoundsError(B, length(B)+1))
72,562✔
509
    Bc = B.chunks
72,562✔
510
    nc = num_bit_chunks(l)
72,562✔
511
    Ai = first(eachindex(A))
72,562✔
512
    @inbounds begin
72,562✔
513
        for i = 1:nc-1
72,565✔
514
            c = UInt64(0)
792,311✔
515
            for j = 0:63
792,311✔
516
                c |= (UInt64(convert(Bool, A[Ai])::Bool) << j)
52,064,927✔
517
                Ai = nextind(A, Ai)
50,707,904✔
518
            end
100,623,497✔
519
            Bc[i] = c
792,311✔
520
        end
1,524,971✔
521
        c = UInt64(0)
72,562✔
522
        tail = _mod64(l - 1) + 1
72,562✔
523
        for j = 0:tail-1
72,565✔
524
            c |= (UInt64(convert(Bool, A[Ai])::Bool) << j)
3,229,481✔
525
            Ai = nextind(A, Ai)
2,575,033✔
526
        end
5,077,510✔
527
        msk = _msk_end(tail)
72,556✔
528
        Bc[nc] = (c & msk) | (Bc[nc] & ~msk)
72,556✔
529
    end
530
    return B
72,556✔
531
end
532

533
(::Type{T})(x::T) where {T<:BitArray} = copy(x)::T
3✔
534
BitArray(x::BitArray) = copy(x)
219✔
535

536
"""
537
    BitArray(itr)
538

539
Construct a [`BitArray`](@ref) generated by the given iterable object.
540
The shape is inferred from the `itr` object.
541

542
# Examples
543
```jldoctest
544
julia> BitArray([1 0; 0 1])
545
2×2 BitMatrix:
546
 1  0
547
 0  1
548

549
julia> BitArray(x+y == 3 for x = 1:2, y = 1:3)
550
2×3 BitMatrix:
551
 0  1  0
552
 1  0  0
553

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

567
convert(::Type{T}, a::AbstractArray) where {T<:BitArray} = a isa T ? a : T(a)::T
262,434✔
568

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

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

582
# generator with known shape or length
583
function gen_bitarray(::HasShape, itr::Generator)
6✔
584
    B = BitArray(undef, size(itr))
267,537✔
585
    return fill_bitarray_from_itr!(B, itr)
267,537✔
586
end
587
function gen_bitarray(::HasLength, itr)
×
588
    b = BitVector(undef, length(itr))
×
589
    return fill_bitarray_from_itr!(b, itr)
×
590
end
591

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

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

602
# The aux functions gen_bitarray_from_itr and fill_bitarray_from_itr! both
603
# use a Vector{Bool} cache for performance reasons
604

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

632
function fill_bitarray_from_itr!(B::BitArray, itr)
267,537✔
633
    n = length(B)
267,537✔
634
    C = Vector{Bool}(undef, bitcache_size)
267,537✔
635
    Bc = B.chunks
267,537✔
636
    ind = 1
267,537✔
637
    cind = 1
267,537✔
638
    y = iterate(itr)
533,508✔
639
    while y !== nothing
26,026,154✔
640
        x, st = y
25,758,617✔
641
        @inbounds C[ind] = x
25,758,617✔
642
        ind += 1
25,758,617✔
643
        if ind > bitcache_size
25,758,617✔
644
            dumpbitcache(Bc, cind, C)
×
645
            cind += bitcache_chunks
×
646
            ind = 1
×
647
        end
648
        y = iterate(itr, st)
51,251,263✔
649
    end
25,758,617✔
650
    if ind > 1
267,537✔
651
        @inbounds C[ind:bitcache_size] .= false
1,063,658,599✔
652
        dumpbitcache(Bc, cind, C)
265,971✔
653
    end
654
    return B
267,537✔
655
end
656

657

658
## Indexing: getindex ##
659

660
@inline function unsafe_bitgetindex(Bc::Vector{UInt64}, i::Int)
6✔
661
    i1, i2 = get_chunks_id(i)
607,143,635✔
662
    u = UInt64(1) << i2
607,011,188✔
663
    @inbounds r = (Bc[i1] & u) != 0
607,143,635✔
664
    return r
432,150,039✔
665
end
666

667
@inline function getindex(B::BitArray, i::Int)
3,546✔
668
    @boundscheck checkbounds(B, i)
269,380,469✔
669
    unsafe_bitgetindex(B.chunks, i)
269,380,469✔
670
end
671

672
## Indexing: setindex! ##
673

674
@inline function unsafe_bitsetindex!(Bc::Array{UInt64}, x::Bool, i::Int)
6✔
675
    i1, i2 = get_chunks_id(i)
99,787,040✔
676
    _unsafe_bitsetindex!(Bc, x, i1, i2)
99,787,040✔
677
end
678

679
@inline function _unsafe_bitsetindex!(Bc::Array{UInt64}, x::Bool, i1::Int, i2::Int)
6✔
680
    u = UInt64(1) << i2
109,341,271✔
681
    @inbounds begin
8,334,673✔
682
        c = Bc[i1]
109,341,322✔
683
        Bc[i1] = ifelse(x, c | u, c & ~u)
109,341,322✔
684
    end
685
end
686

687
@inline function setindex!(B::BitArray, x, i::Int)
6,075✔
688
    @boundscheck checkbounds(B, i)
52,691,998✔
689
    unsafe_bitsetindex!(B.chunks, convert(Bool, x), i)
52,691,998✔
690
    return B
52,440,392✔
691
end
692

693
indexoffset(i) = first(i)-1
298,918✔
694
indexoffset(::Colon) = 0
×
695

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

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

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

737
## Dequeue functionality ##
738

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

743
    Bc = B.chunks
780✔
744

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

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

773
append!(B::BitVector, items) = append!(B, BitVector(items))
31,320✔
774
append!(A::Vector{Bool}, items::BitVector) = append!(A, Array(items))
×
775

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

793
prepend!(B::BitVector, items) = prepend!(B, BitArray(items))
6,264✔
794
prepend!(A::Vector{Bool}, items::BitVector) = prepend!(A, Array(items))
×
795

796
function sizehint!(B::BitVector, sz::Integer)
×
797
    sizehint!(B.chunks, num_bit_chunks(sz))
×
798
    return B
×
799
end
800

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

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

826
    l = _mod64(length(B))
×
827
    l == 1 && _deleteend!(B.chunks, 1)
×
828
    B.len -= 1
×
829

830
    return item
×
831
end
832

833
function pushfirst!(B::BitVector, item)
780✔
834
    item = convert(Bool, item)
780✔
835

836
    Bc = B.chunks
780✔
837

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

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

860
        Bc = B.chunks
×
861

862
        for i = 1 : length(Bc) - 1
×
863
            Bc[i] = (Bc[i] >>> 1) | (Bc[i+1] << 63)
×
864
        end
×
865

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

875
    return item
×
876
end
877

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

885
    Bc = B.chunks
807✔
886

887
    k, j = get_chunks_id(i)
807✔
888

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

896
    for t = length(Bc) : -1 : k + 1
1,327✔
897
        Bc[t] = (Bc[t] << 1) | (Bc[t - 1] >>> 63)
812✔
898
    end
1,116✔
899

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

907
function _deleteat!(B::BitVector, i::Int)
×
908
    k, j = get_chunks_id(i)
×
909

910
    msk_bef = _msk64 >>> (63 - j)
×
911
    msk_aft = ~msk_bef
×
912
    msk_bef >>>= 1
×
913

914
    Bc = B.chunks
×
915

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

922
        for t = k + 1 : length(Bc) - 1
×
923
            Bc[t] = (Bc[t] >>> 1) | (Bc[t + 1] << 63)
×
924
        end
×
925

926
        l = _mod64(length(B))
×
927

928
        if l == 1
×
929
            _deleteend!(Bc, 1)
×
930
        elseif length(Bc) > k
×
931
            Bc[end] >>>= 1
×
932
        end
933
    end
934

935
    B.len -= 1
×
936

937
    return B
×
938
end
939

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

946
    return _deleteat!(B, i)
807✔
947
end
948

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

956
    Bc = B.chunks
×
957
    new_l = length(B) - length(r)
×
958
    delta_k = num_bit_chunks(new_l) - length(Bc)
×
959

960
    copy_chunks!(Bc, i_f, Bc, i_l+1, n-i_l)
×
961

962
    delta_k < 0 && _deleteend!(Bc, -delta_k)
×
963

964
    B.len = new_l
×
965

966
    if new_l > 0
×
967
        Bc[end] &= _msk_end(new_l)
×
968
    end
969

970
    return B
×
971
end
972

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

978
    Bc = B.chunks
100,662✔
979

980
    (p, s) = y
100,662✔
981
    checkbounds(B, p)
100,677✔
982
    p isa Bool && throw(ArgumentError("invalid index $p of type Bool"))
100,647✔
983
    q = p+1
100,644✔
984
    new_l -= 1
100,644✔
985
    y = iterate(inds, s)
100,644✔
986
    while y !== nothing
4,445,014✔
987
        (i, s) = y
4,344,385✔
988
        if !(q <= i <= n)
4,344,385✔
989
            i isa Bool && throw(ArgumentError("invalid index $i of type Bool"))
15✔
990
            i < q && throw(ArgumentError("indices must be unique and sorted"))
12✔
991
            throw(BoundsError(B, i))
6✔
992
        end
993
        new_l -= 1
4,344,370✔
994
        if i > q
4,344,370✔
995
            copy_chunks!(Bc, Int(p), Bc, Int(q), Int(i-q))
2,147,290✔
996
            p += i-q
2,147,290✔
997
        end
998
        q = i+1
4,344,370✔
999
        y = iterate(inds, s)
4,344,370✔
1000
    end
4,344,370✔
1001

1002
    q <= n && copy_chunks!(Bc, Int(p), Bc, Int(q), Int(n-q+1))
100,632✔
1003

1004
    delta_k = num_bit_chunks(new_l) - length(Bc)
100,629✔
1005
    delta_k < 0 && _deleteend!(Bc, -delta_k)
124,665✔
1006

1007
    B.len = new_l
100,629✔
1008

1009
    if new_l > 0
100,629✔
1010
        Bc[end] &= _msk_end(new_l)
100,629✔
1011
    end
1012

1013
    return B
100,629✔
1014
end
1015

1016
function deleteat!(B::BitVector, inds::AbstractVector{Bool})
12,012✔
1017
    length(inds) == length(B) || throw(BoundsError(B, inds))
12,015✔
1018

1019
    n = new_l = length(B)
12,009✔
1020
    y = findfirst(inds)
29,220✔
1021
    y === nothing && return B
12,009✔
1022

1023
    Bc = B.chunks
11,427✔
1024

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

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

1045
    delta_k = num_bit_chunks(new_l) - length(Bc)
11,427✔
1046
    delta_k < 0 && _deleteend!(Bc, -delta_k)
11,427✔
1047

1048
    B.len = new_l
11,427✔
1049

1050
    if new_l > 0
11,427✔
1051
        Bc[end] &= _msk_end(new_l)
10,788✔
1052
    end
1053

1054
    return B
11,427✔
1055
end
1056

1057
keepat!(B::BitVector, inds) = _keepat!(B, inds)
6✔
1058
keepat!(B::BitVector, inds::AbstractVector{Bool}) = _keepat!(B, inds)
3✔
1059

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

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

1074
const _default_bit_splice = BitVector()
1075

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

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

1087
    Bins = convert(BitArray, ins)
224,118✔
1088

1089
    if (i_f > n)
224,118✔
1090
        append!(B, Bins)
207✔
1091
        return BitVector()
108✔
1092
    end
1093

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

1096
    Bc = B.chunks
224,010✔
1097

1098
    lins = length(Bins)
224,010✔
1099
    ldel = length(r)
224,010✔
1100

1101
    new_l = length(B) + lins - ldel
224,010✔
1102
    delta_k = num_bit_chunks(new_l) - length(Bc)
224,010✔
1103

1104
    delta_k > 0 && _growend!(Bc, delta_k)
224,010✔
1105

1106
    copy_chunks!(Bc, i_f+lins, Bc, i_l+1, n-i_l)
224,010✔
1107
    copy_chunks!(Bc, i_f, Bins.chunks, 1, lins)
224,010✔
1108

1109
    delta_k < 0 && _deleteend!(Bc, -delta_k)
341,133✔
1110

1111
    B.len = new_l
224,010✔
1112

1113
    if new_l > 0
224,010✔
1114
        Bc[end] &= _msk_end(new_l)
223,998✔
1115
    end
1116

1117
    return v
224,010✔
1118
end
1119

1120
function splice!(B::BitVector, r::Union{AbstractUnitRange{Int}, Integer}, ins)
37,656✔
1121
    Bins = BitVector(undef, length(ins))
37,656✔
1122
    i = 1
37,656✔
1123
    for x in ins
75,312✔
1124
        Bins[i] = Bool(x)
4,023,064✔
1125
        i += 1
4,023,064✔
1126
    end
8,046,128✔
1127
    return splice!(B, r, Bins)
37,656✔
1128
end
1129

1130

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

1137
## Unary operators ##
1138

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

1168
## Binary arithmetic operators ##
1169

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

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

1194
## promotion to complex ##
1195

1196
# TODO?
1197

1198
## comparison operators ##
1199

1200
function (==)(A::BitArray, B::BitArray)
12,078✔
1201
    size(A) != size(B) && return false
3,600,504✔
1202
    return A.chunks == B.chunks
1,800,255✔
1203
end
1204

1205

1206
## Data movement ##
1207

1208
# TODO some of this could be optimized
1209

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

1217
    B = similar(A)
12✔
1218

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

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

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

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

1272
    n = length(B)
×
1273
    n == 0 && return B
×
1274

1275
    k = _mod64(n+63) + 1
×
1276
    h = 64 - k
×
1277

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

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

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

1308
    return B
×
1309
end
1310

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

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

1327
"""
1328
    >>(B::BitVector, n)::BitVector
1329

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

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

1345
julia> B >> 1
1346
5-element BitVector:
1347
 0
1348
 1
1349
 0
1350
 1
1351
 0
1352

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

1364
# signed integer version of shift operators with handling of negative values
1365
"""
1366
    <<(B::BitVector, n)::BitVector
1367

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

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

1383
julia> B << 1
1384
5-element BitVector:
1385
 0
1386
 1
1387
 0
1388
 0
1389
 0
1390

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

1402
"""
1403
    >>>(B::BitVector, n)::BitVector
1404

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

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

1429
circshift!(B::BitVector, i::Integer) = circshift!(B, B, i)
48✔
1430

1431
## count & find ##
1432

1433
function bitcount(Bc::Vector{UInt64}; init::T=0) where {T}
997,805✔
1434
    n::T = init
724,763✔
1435
    @inbounds for i = 1:length(Bc)
1,088,365✔
1436
        n = (n + count_ones(Bc[i])) % T
660,637✔
1437
    end
805,850✔
1438
    return n
727,843✔
1439
end
1440

1441
_count(::typeof(identity), B::BitArray, ::Colon, init) = bitcount(B.chunks; init)
409,568✔
1442

1443
function unsafe_bitfindnext(Bc::Vector{UInt64}, start::Int)
1444
    chunk_start = _div64(start-1)+1
1,041,426✔
1445
    within_chunk_start = _mod64(start-1)
1,041,426✔
1446
    mask = _msk64 << within_chunk_start
1,041,426✔
1447

1448
    @inbounds begin
870,828✔
1449
        if Bc[chunk_start] & mask != 0
1,041,640✔
1450
            return (chunk_start-1) << 6 + trailing_zeros(Bc[chunk_start] & mask) + 1
594,617✔
1451
        end
1452

1453
        for i = chunk_start+1:length(Bc)
452,451✔
1454
            if Bc[i] != 0
216,508✔
1455
                return (i-1) << 6 + trailing_zeros(Bc[i]) + 1
119,036✔
1456
            end
1457
        end
192,772✔
1458
    end
1459
    return nothing
327,987✔
1460
end
1461

1462
# returns the index of the next true element, or nothing if all false
1463
function findnext(B::BitArray, start::Integer)
137,235✔
1464
    start = Int(start)
184,125✔
1465
    start > 0 || throw(BoundsError(B, start))
184,119✔
1466
    start > length(B) && return nothing
184,107✔
1467
    unsafe_bitfindnext(B.chunks, start)
181,068✔
1468
end
1469

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

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

1477
    Bc = B.chunks
167,679✔
1478
    l = length(Bc)
167,679✔
1479
    l == 0 && return nothing
167,679✔
1480

1481
    chunk_start = _div64(start-1)+1
167,679✔
1482
    within_chunk_start = _mod64(start-1)
167,679✔
1483
    mask = ~(_msk64 << within_chunk_start)
167,679✔
1484

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

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

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

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

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

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

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

1547
# returns the index of the previous true element, or nothing if all false
1548
function findprev(B::BitArray, start::Integer)
37,899✔
1549
    start = Int(start)
41,116✔
1550
    start > 0 || return nothing
41,110✔
1551
    start > length(B) && throw(BoundsError(B, start))
41,098✔
1552
    unsafe_bitfindprev(B.chunks, start)
41,092✔
1553
end
1554

1555
function findprevnot(B::BitArray, start::Int)
65,048✔
1556
    start = Int(start)
65,048✔
1557
    start > 0 || return nothing
65,054✔
1558
    start > length(B) && throw(BoundsError(B, start))
65,042✔
1559

1560
    Bc = B.chunks
65,036✔
1561

1562
    chunk_start = _div64(start-1)+1
65,036✔
1563
    mask = ~_msk_end(start)
65,036✔
1564

1565
    @inbounds begin
65,036✔
1566
        if Bc[chunk_start] | mask != _msk64
65,036✔
1567
            return (chunk_start-1) << 6 + (64 - leading_ones(Bc[chunk_start] | mask))
52,364✔
1568
        end
1569

1570
        for i = chunk_start-1:-1:1
25,314✔
1571
            if Bc[i] != _msk64
13,243✔
1572
                return (i-1) << 6 + (64 - leading_ones(Bc[i]))
12,632✔
1573
            end
1574
        end
1,203✔
1575
    end
1576
    return nothing
40✔
1577
end
1578
findlastnot(B::BitArray) = findprevnot(B, length(B))
3✔
1579

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

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

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

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

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

1635
# findall helper functions
1636
# Generic case (>2 dimensions)
1637
function allindices!(I, B::BitArray)
1638
    ind = first(keys(B))
24✔
1639
    for k = 1:length(B)
24✔
1640
        I[k] = ind
1,518✔
1641
        ind = nextind(B, ind)
2,274✔
1642
    end
3,012✔
1643
end
1644

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

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

1659
@inline _overflowind(i1, irest::Tuple{}, size) = (i1, irest)
17,899✔
1660
@inline function _overflowind(i1, irest, size)
1661
    i2 = irest[1]
10,606✔
1662
    while i1 > size[1]
16,831✔
1663
        i1 -= size[1]
6,225✔
1664
        i2 += 1
6,225✔
1665
    end
6,225✔
1666
    i2, irest = _overflowind(i2, tail(irest), tail(size))
10,606✔
1667
    return (i1, (i2, irest...))
10,606✔
1668
end
1669

1670
@inline _toind(i1, irest::Tuple{}) = i1
244✔
1671
@inline _toind(i1, irest) = CartesianIndex(i1, irest...)
3,716✔
1672

1673
function findall(B::BitArray)
499✔
1674
    nnzB = count(B)
631✔
1675
    I = Vector{eltype(keys(B))}(undef, nnzB)
499✔
1676
    nnzB == 0 && return I
499✔
1677
    nnzB == length(B) && (allindices!(I, B); return I)
228✔
1678
    Bc = B.chunks
201✔
1679
    Bs = size(B)
201✔
1680
    Bi = i1 = i = 1
201✔
1681
    irest = ntuple(one, ndims(B) - 1)
201✔
1682
    c = Bc[1]
201✔
1683
    @inbounds while true
201✔
1684
        while c == 0
4,161✔
1685
            Bi == length(Bc) && return I
300✔
1686
            i1 += 64
99✔
1687
            Bi += 1
99✔
1688
            c = Bc[Bi]
99✔
1689
        end
99✔
1690

1691
        tz = trailing_zeros(c)
3,960✔
1692
        c = _blsr(c)
3,960✔
1693

1694
        i1, irest = _overflowind(i1 + tz, irest, Bs)
3,960✔
1695
        I[i] = _toind(i1, irest)
3,960✔
1696
        i += 1
3,960✔
1697
        i1 -= tz
3,960✔
1698
    end
3,960✔
1699
end
1700

1701
# For performance
1702
findall(::typeof(!iszero), B::BitArray) = findall(B)
3✔
1703

1704
## Reductions ##
1705

1706
_sum(A::BitArray, dims)    = reduce(+, A, dims=dims)
×
1707
_sum(B::BitArray, ::Colon) = count(B)
×
1708

1709
function all(B::BitArray)
3,189✔
1710
    isempty(B) && return true
10,558✔
1711
    Bc = B.chunks
10,552✔
1712
    @inbounds begin
10,552✔
1713
        for i = 1:length(Bc)-1
10,555✔
1714
            Bc[i] == _msk64 || return false
8,115✔
1715
        end
14,364✔
1716
        Bc[end] == _msk_end(B) || return false
11,071✔
1717
    end
1718
    return true
9,597✔
1719
end
1720

1721
function any(B::BitArray)
4,647✔
1722
    isempty(B) && return false
283,444✔
1723
    Bc = B.chunks
283,441✔
1724
    @inbounds begin
122,506✔
1725
        for i = 1:length(Bc)
401,315✔
1726
            Bc[i] == 0 || return true
578,005✔
1727
        end
162,973✔
1728
    end
1729
    return false
46,909✔
1730
end
1731

1732
minimum(B::BitArray) = isempty(B) ? throw(ArgumentError("argument must be non-empty")) : all(B)
6✔
1733
maximum(B::BitArray) = isempty(B) ? throw(ArgumentError("argument must be non-empty")) : any(B)
6✔
1734

1735
## map over bitarrays ##
1736

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

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

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

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

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

1810
## Filter ##
1811

1812
function filter(f, Bs::BitArray)
×
1813
    boolmap::Array{Bool} = map(f, Bs)
×
1814
    Bs[boolmap]
×
1815
end
1816

1817

1818
## Concatenation ##
1819

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

1833
function vcat(V::BitVector...)
1,276✔
1834
    n = 0
1,276✔
1835
    for Vk in V
1,276✔
1836
        n += length(Vk)
4,227✔
1837
    end
5,491✔
1838
    B = BitVector(undef, n)
1,276✔
1839
    j = 1
1,276✔
1840
    for Vk in V
1,276✔
1841
        copy_chunks!(B.chunks, j, Vk.chunks, 1, length(Vk))
4,227✔
1842
        j += length(Vk)
4,227✔
1843
    end
5,491✔
1844
    return B
1,276✔
1845
end
1846

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

1860
    B = BitMatrix(undef, nrows, ncols)
3✔
1861

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

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

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

1907
# hvcat -> use fallbacks in abstractarray.jl
1908

1909

1910
# BitArray I/O
1911

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

1924
sizeof(B::BitArray) = sizeof(B.chunks)
6✔
1925

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