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

JuliaLang / julia / #37477

pending completion
#37477

push

local

web-flow
Allow external lattice elements to properly union split (#49030)

Currently `MustAlias` is the only lattice element that is allowed
to widen to union types. However, there are others in external
packages. Expand the support we have for this in order to allow
union splitting of lattice elements.

Co-authored-by: Shuhei Kadowaki <40514306+aviatesk@users.noreply.github.com>

26 of 26 new or added lines in 5 files covered. (100.0%)

71476 of 82705 relevant lines covered (86.42%)

34756248.54 hits per line

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

93.02
/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
210,918✔
29
        n = 1
4,721✔
30
        i = 1
4,721✔
31
        for d in dims
22,806,119✔
32
            d >= 0 || throw(ArgumentError("dimension size must be ≥ 0, got $d for dimension $i"))
22,814,267✔
33
            n *= d
22,814,267✔
34
            i += 1
20,330✔
35
        end
22,822,002✔
36
        nc = num_bit_chunks(n)
22,806,046✔
37
        chunks = Vector{UInt64}(undef, nc)
22,806,119✔
38
        nc > 0 && (chunks[end] = UInt64(0))
22,806,046✔
39
        b = new(chunks, n)
22,806,119✔
40
        N != 1 && (b.dims = dims)
12,109✔
41
        return b
22,806,119✔
42
    end
43
end
44

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

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

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

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

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

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

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

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

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

101
## utility functions ##
102

103
length(B::BitArray) = B.len
95,759,476✔
104
size(B::BitVector) = (B.len,)
46,248,708✔
105
size(B::BitArray) = B.dims
3,928,634✔
106

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

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

114
IndexStyle(::Type{<:BitArray}) = IndexLinear()
1,020,163✔
115

116
## aux functions ##
117

118
const _msk64 = ~UInt64(0)
119
@inline _div64(l) = l >> 6
797,680,684✔
120
@inline _mod64(l) = l & 63
695,369,217✔
121
@inline _blsr(x)= x & (x-1) #zeros the last set bit. Has native instruction on many archs. needed in multidimensional.jl
150,089,673✔
122
@inline _msk_end(l::Int) = _msk64 >>> _mod64(-l)
716,332✔
123
@inline _msk_end(B::BitArray) = _msk_end(length(B))
208,130✔
124
num_bit_chunks(n::Int) = _div64(n+63)
23,274,342✔
125

126
@inline get_chunks_id(i::Int) = _div64(i-1)+1, _mod64(i-1)
152,706,806✔
127

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

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

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

150
    delta_kd = kd1 - kd0
1,113,237✔
151
    delta_ks = ks1 - ks0
1,113,237✔
152

153
    u = _msk64
×
154
    if delta_kd == 0
1,113,237✔
155
        msk_d0 = ~(u << ld0) | (u << (ld1+1))
832,411✔
156
    else
157
        msk_d0 = ~(u << ld0)
280,826✔
158
        msk_d1 = (u << (ld1+1))
280,826✔
159
    end
160
    if delta_ks == 0
1,113,237✔
161
        msk_s0 = (u << ls0) & ~(u << (ls1+1))
816,400✔
162
    else
163
        msk_s0 = (u << ls0)
296,837✔
164
    end
165

166
    chunk_s0 = glue_src_bitchunks(src, ks0, ks1, msk_s0, ls0)
1,113,237✔
167

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

170
    delta_kd == 0 && return
1,113,237✔
171

172
    for i = 1 : kd1 - kd0 - 1
420,575✔
173
        chunk_s1 = glue_src_bitchunks(src, ks0 + i, ks1, msk_s0, ls0)
262,449✔
174

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

177
        dest[kd0 + i] = chunk_s
262,449✔
178

179
        chunk_s0 = chunk_s1
×
180
    end
385,149✔
181

182
    if ks1 >= ks0 + delta_kd
280,826✔
183
        chunk_s1 = glue_src_bitchunks(src, ks0 + delta_kd, ks1, msk_s0, ls0)
176,570✔
184
    else
185
        chunk_s1 = UInt64(0)
×
186
    end
187

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

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

192
    return
280,826✔
193
end
194

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

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

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

214
        if delta_kd == 0
67,171✔
215
            msk_d0 = ~(u << ld0) | (u << (ld1+1))
16,610✔
216
        else
217
            msk_d0 = ~(u << ld0)
50,561✔
218
            msk_d1 = (u << (ld1+1))
50,561✔
219
        end
220
        if delta_ks == 0
67,171✔
221
            msk_s0 = (u << ls0) & ~(u << (ls1+1))
6,915✔
222
        else
223
            msk_s0 = (u << ls0)
60,256✔
224
        end
225

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

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

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

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

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

248
    u = _msk64
×
249
    if k1 == k0
2,255✔
250
        msk0 = (u << l0) & ~(u << (l1+1))
2,153✔
251
    else
252
        msk0 = (u << l0)
102✔
253
        msk1 = ~(u << (l1+1))
102✔
254
    end
255
    @inbounds if x
2,255✔
256
        Bc[k0] |= msk0
2,080✔
257
        for k = k0+1:k1-1
2,118✔
258
            Bc[k] = u
180✔
259
        end
322✔
260
        k1 > k0 && (Bc[k1] |= msk1)
2,080✔
261
    else
262
        Bc[k0] &= ~msk0
175✔
263
        for k = k0+1:k1-1
200✔
264
            Bc[k] = 0
114✔
265
        end
203✔
266
        k1 > k0 && (Bc[k1] &= ~msk1)
2,430✔
267
    end
268
end
269

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

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

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

287
    delta_kd = kd1 - kd0
31,955✔
288

289
    u = _msk64
8✔
290
    if delta_kd == 0
31,955✔
291
        msk_d0 = msk_d1 = ~(u << ld0) | (u << (ld1+1))
14,829✔
292
        lt0 = ld1
14,829✔
293
    else
294
        msk_d0 = ~(u << ld0)
17,126✔
295
        msk_d1 = (u << (ld1+1))
17,126✔
296
        lt0 = 63
6✔
297
    end
298

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

311
    nc = _div64(numbits - ind + pos_s)
31,955✔
312
    nc8 = (nc >>> 3) << 3
31,955✔
313
    if nc8 > 0
31,955✔
314
        ind8 = 1
1✔
315
        P8 = Ptr{UInt64}(pointer(C, ind)) # unaligned i64 pointer
1,406✔
316
        @inbounds for i = 1:nc8
2,812✔
317
            c = UInt64(0)
8✔
318
            for j = 0:7
26,208✔
319
                # unaligned load
320
                c |= (pack8bools(unsafe_load(P8, ind8)) << (j<<3))
209,664✔
321
                ind8 += 1
209,664✔
322
            end
393,120✔
323
            Bc[bind] = c
26,208✔
324
            bind += 1
26,208✔
325
        end
51,010✔
326
        ind += (ind8-1) << 3
1,406✔
327
    end
328
    @inbounds for i = (nc8+1):nc
47,998✔
329
        c = UInt64(0)
18✔
330
        for j = 0:63
72,130✔
331
            c |= (UInt64(C[ind]) << j)
4,616,320✔
332
            ind += 1
4,616,320✔
333
        end
9,160,510✔
334
        Bc[bind] = c
72,130✔
335
        bind += 1
72,130✔
336
    end
128,217✔
337
    @inbounds if bind ≤ kd1
31,955✔
338
        @assert bind == kd1
13,209✔
339
        c = UInt64(0)
7✔
340
        for j = 0:ld1
26,418✔
341
            c |= (UInt64(C[ind]) << j)
458,710✔
342
            ind += 1
458,710✔
343
        end
904,211✔
344
        Bc[kd1] = (Bc[kd1] & msk_d1) | (c & ~msk_d1)
13,209✔
345
    end
346
end
347

348
## More definitions in multidimensional.jl
349

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

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

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

359

360
## custom iterator ##
361
function iterate(B::BitArray, i::Int=0)
62,629,263✔
362
    i >= length(B) && return nothing
64,013,081✔
363
    (B.chunks[_div64(i)+1] & (UInt64(1)<<_mod64(i)) != 0, i+1)
63,525,710✔
364
end
365

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

368
similar(B::BitArray) = BitArray(undef, size(B))
148,926✔
369
similar(B::BitArray, dims::Int...) = BitArray(undef, dims)
1✔
370
similar(B::BitArray, dims::Dims) = BitArray(undef, dims...)
×
371

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

377
function fill!(B::BitArray, x)
22,421,590✔
378
    y = convert(Bool, x)
72✔
379
    isempty(B) && return B
22,421,590✔
380
    Bc = B.chunks
22,420,459✔
381
    if !y
22,420,459✔
382
        fill!(Bc, 0)
23,427,197✔
383
    else
384
        fill!(Bc, _msk64)
8,116✔
385
        Bc[end] &= _msk_end(B)
1,013✔
386
    end
387
    return B
22,420,459✔
388
end
389

390
"""
391
    falses(dims)
392

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

395
# Examples
396
```jldoctest
397
julia> falses(2,3)
398
2×3 BitMatrix:
399
 0  0  0
400
 0  0  0
401
```
402
"""
403
falses(dims::DimOrInd...) = falses(dims)
22,367,466✔
404
falses(dims::NTuple{N, Union{Integer, OneTo}}) where {N} = falses(map(to_dim, dims))
×
405
falses(dims::NTuple{N, Integer}) where {N} = fill!(BitArray(undef, dims), false)
22,368,236✔
406
falses(dims::Tuple{}) = fill!(BitArray(undef, dims), false)
10✔
407

408
"""
409
    trues(dims)
410

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

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

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

436
function copyto!(dest::BitArray, src::BitArray)
146,928✔
437
    length(src) > length(dest) && throw(BoundsError(dest, length(dest)+1))
146,928✔
438
    destc = dest.chunks; srcc = src.chunks
293,854✔
439
    nc = min(length(destc), length(srcc))
146,927✔
440
    nc == 0 && return dest
146,927✔
441
    @inbounds begin
34✔
442
        for i = 1 : nc - 1
289,325✔
443
            destc[i] = srcc[i]
575,639✔
444
        end
1,008,878✔
445
        if length(src) == length(dest)
146,925✔
446
            destc[nc] = srcc[nc]
146,923✔
447
        else
448
            msk_s = _msk_end(src)
2✔
449
            msk_d = ~msk_s
2✔
450
            destc[nc] = (msk_d & destc[nc]) | (msk_s & srcc[nc])
2✔
451
        end
452
    end
453
    return dest
146,925✔
454
end
455

456
function unsafe_copyto!(dest::BitArray, doffs::Integer, src::Union{BitArray,Array}, soffs::Integer, n::Integer)
61,085✔
457
    copy_to_bitarray_chunks!(dest.chunks, Int(doffs), src, Int(soffs), Int(n))
61,085✔
458
    return dest
61,085✔
459
end
460

461
copyto!(dest::BitArray, doffs::Integer, src::Union{BitArray,Array}, soffs::Integer, n::Integer) =
141,076✔
462
    _copyto_int!(dest, Int(doffs), src, Int(soffs), Int(n))
463
function _copyto_int!(dest::BitArray, doffs::Int, src::Union{BitArray,Array}, soffs::Int, n::Int)
141,076✔
464
    n == 0 && return dest
141,076✔
465
    n < 0 && throw(ArgumentError("Number of elements to copy must be nonnegative."))
140,946✔
466
    soffs < 1 && throw(BoundsError(src, soffs))
140,945✔
467
    doffs < 1 && throw(BoundsError(dest, doffs))
140,944✔
468
    soffs+n-1 > length(src) && throw(BoundsError(src, length(src)+1))
140,941✔
469
    doffs+n-1 > length(dest) && throw(BoundsError(dest, length(dest)+1))
82,571✔
470
    return unsafe_copyto!(dest, doffs, src, soffs, n)
61,069✔
471
end
472

473
function copyto!(dest::BitArray, src::Array)
17✔
474
    length(src) > length(dest) && throw(BoundsError(dest, length(dest)+1))
17✔
475
    length(src) == 0 && return dest
17✔
476
    return unsafe_copyto!(dest, 1, src, 1, length(src))
16✔
477
end
478

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

493
## Constructors ##
494

495
function Array{T,N}(B::BitArray{N}) where {T,N}
275,528✔
496
    A = Array{T,N}(undef, size(B))
275,528✔
497
    Bc = B.chunks
275,528✔
498
    @inbounds for i = 1:length(A)
548,097✔
499
        A[i] = unsafe_bitgetindex(Bc, i)
97,453,326✔
500
    end
194,634,083✔
501
    return A
275,528✔
502
end
503

504
BitArray(A::AbstractArray{<:Any,N}) where {N} = BitArray{N}(A)
14,686✔
505

506
function BitArray{N}(A::AbstractArray{T,N}) where N where T
20,783✔
507
    B = BitArray(undef, convert(Dims{N}, size(A)::Dims{N}))
20,783✔
508
    _checkaxs(axes(B), axes(A))
20,783✔
509
    _copyto_bitarray!(B, A)
20,781✔
510
    return B::BitArray{N}
20,779✔
511
end
512

513
function _copyto_bitarray!(B::BitArray, A::AbstractArray)
20,782✔
514
    l = length(A)
20,782✔
515
    l == 0 && return B
20,782✔
516
    l > length(B) && throw(BoundsError(B, length(B)+1))
19,213✔
517
    Bc = B.chunks
19,213✔
518
    nc = num_bit_chunks(l)
19,213✔
519
    Ai = first(eachindex(A))
19,213✔
520
    @inbounds begin
19,213✔
521
        for i = 1:nc-1
29,417✔
522
            c = UInt64(0)
17,013✔
523
            for j = 0:63
17,013✔
524
                c |= (UInt64(convert(Bool, A[Ai])::Bool) << j)
1,540,976✔
525
                Ai = nextind(A, Ai)
1,088,832✔
526
            end
2,160,651✔
527
            Bc[i] = c
17,013✔
528
        end
23,822✔
529
        c = UInt64(0)
19,213✔
530
        tail = _mod64(l - 1) + 1
19,213✔
531
        for j = 0:tail-1
38,426✔
532
            c |= (UInt64(convert(Bool, A[Ai])::Bool) << j)
830,937✔
533
            Ai = nextind(A, Ai)
613,234✔
534
        end
1,207,257✔
535
        msk = _msk_end(tail)
19,211✔
536
        Bc[nc] = (c & msk) | (Bc[nc] & ~msk)
19,211✔
537
    end
538
    return B
19,211✔
539
end
540

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

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

549
"""
550
    BitArray(itr)
551

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

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

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

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

580
convert(::Type{T}, a::AbstractArray) where {T<:BitArray} = a isa T ? a : T(a)::T
216,566✔
581

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

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

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

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

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

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

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

645
function fill_bitarray_from_itr!(B::BitArray, itr)
4,216✔
646
    n = length(B)
4,179✔
647
    C = Vector{Bool}(undef, bitcache_size)
4,216✔
648
    Bc = B.chunks
4,216✔
649
    ind = 1
4,179✔
650
    cind = 1
4,179✔
651
    y = iterate(itr)
7,910✔
652
    while y !== nothing
307,566✔
653
        x, st = y
303,138✔
654
        @inbounds C[ind] = x
303,350✔
655
        ind += 1
303,350✔
656
        if ind > bitcache_size
303,350✔
657
            dumpbitcache(Bc, cind, C)
×
658
            cind += bitcache_chunks
×
659
            ind = 1
×
660
        end
661
        y = iterate(itr, st)
603,006✔
662
    end
303,350✔
663
    if ind > 1
4,216✔
664
        @inbounds C[ind:bitcache_size] .= false
14,827,274✔
665
        dumpbitcache(Bc, cind, C)
3,694✔
666
    end
667
    return B
4,216✔
668
end
669

670

671
## Indexing: getindex ##
672

673
@inline function unsafe_bitgetindex(Bc::Vector{UInt64}, i::Int)
97,891,090✔
674
    i1, i2 = get_chunks_id(i)
139,347,897✔
675
    u = UInt64(1) << i2
139,305,738✔
676
    @inbounds r = (Bc[i1] & u) != 0
139,347,897✔
677
    return r
×
678
end
679

680
@inline function getindex(B::BitArray, i::Int)
5,152,546✔
681
    @boundscheck checkbounds(B, i)
41,854,678✔
682
    unsafe_bitgetindex(B.chunks, i)
41,854,678✔
683
end
684

685
## Indexing: setindex! ##
686

687
@inline function unsafe_bitsetindex!(Bc::Array{UInt64}, x::Bool, i::Int)
121,429✔
688
    i1, i2 = get_chunks_id(i)
8,516,238✔
689
    _unsafe_bitsetindex!(Bc, x, i1, i2)
8,516,238✔
690
end
691

692
@inline function _unsafe_bitsetindex!(Bc::Array{UInt64}, x::Bool, i1::Int, i2::Int)
38✔
693
    u = UInt64(1) << i2
324,520,912✔
694
    @inbounds begin
38✔
695
        c = Bc[i1]
379,768,988✔
696
        Bc[i1] = ifelse(x, c | u, c & ~u)
379,768,988✔
697
    end
698
end
699

700
@inline function setindex!(B::BitArray, x, i::Int)
3,929,794✔
701
    @boundscheck checkbounds(B, i)
8,471,361✔
702
    unsafe_bitsetindex!(B.chunks, convert(Bool, x), i)
8,472,129✔
703
    return B
8,471,361✔
704
end
705

706
indexoffset(i) = first(i)-1
83,116✔
707
indexoffset(::Colon) = 0
×
708

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

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

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

750
## Dequeue functionality ##
751

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

756
    Bc = B.chunks
260✔
757

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

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

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

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

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

809
function sizehint!(B::BitVector, sz::Integer)
×
810
    ccall(:jl_array_sizehint, Cvoid, (Any, UInt), B.chunks, num_bit_chunks(sz))
×
811
    return B
×
812
end
813

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

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

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

843
    return item
260✔
844
end
845

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

849
    Bc = B.chunks
260✔
850

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

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

873
        Bc = B.chunks
260✔
874

875
        for i = 1 : length(Bc) - 1
456✔
876
            Bc[i] = (Bc[i] >>> 1) | (Bc[i+1] << 63)
400✔
877
        end
604✔
878

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

888
    return item
260✔
889
end
890

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

898
    Bc = B.chunks
269✔
899

900
    k, j = get_chunks_id(i)
269✔
901

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

909
    for t = length(Bc) : -1 : k + 1
433✔
910
        Bc[t] = (Bc[t] << 1) | (Bc[t - 1] >>> 63)
249✔
911
    end
334✔
912

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

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

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

927
    Bc = B.chunks
538✔
928

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

935
        for t = k + 1 : length(Bc) - 1
671✔
936
            Bc[t] = (Bc[t] >>> 1) | (Bc[t + 1] << 63)
187✔
937
        end
241✔
938

939
        l = _mod64(length(B))
538✔
940

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

948
    B.len -= 1
538✔
949

950
    return B
538✔
951
end
952

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

959
    return _deleteat!(B, i)
269✔
960
end
961

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

969
    Bc = B.chunks
33,933✔
970
    new_l = length(B) - length(r)
33,933✔
971
    delta_k = num_bit_chunks(new_l) - length(Bc)
33,933✔
972

973
    copy_chunks!(Bc, i_f, Bc, i_l+1, n-i_l)
33,933✔
974

975
    delta_k < 0 && _deleteend!(Bc, -delta_k)
33,933✔
976

977
    B.len = new_l
33,933✔
978

979
    if new_l > 0
33,933✔
980
        Bc[end] &= _msk_end(new_l)
33,932✔
981
    end
982

983
    return B
33,933✔
984
end
985

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

991
    Bc = B.chunks
33,532✔
992

993
    (p, s) = y
33,532✔
994
    checkbounds(B, p)
33,537✔
995
    p isa Bool && throw(ArgumentError("invalid index $p of type Bool"))
33,527✔
996
    q = p+1
33,526✔
997
    new_l -= 1
33,526✔
998
    y = iterate(inds, s)
33,913✔
999
    while y !== nothing
1,480,635✔
1000
        (i, s) = y
1,447,114✔
1001
        if !(q <= i <= n)
1,447,114✔
1002
            i isa Bool && throw(ArgumentError("invalid index $i of type Bool"))
5✔
1003
            i < q && throw(ArgumentError("indices must be unique and sorted"))
4✔
1004
            throw(BoundsError(B, i))
2✔
1005
        end
1006
        new_l -= 1
1,447,109✔
1007
        if i > q
1,447,109✔
1008
            copy_chunks!(Bc, Int(p), Bc, Int(q), Int(i-q))
715,798✔
1009
            p += i-q
715,798✔
1010
        end
1011
        q = i+1
1,447,109✔
1012
        y = iterate(inds, s)
1,480,243✔
1013
    end
1,447,109✔
1014

1015
    q <= n && copy_chunks!(Bc, Int(p), Bc, Int(q), Int(n-q+1))
33,522✔
1016

1017
    delta_k = num_bit_chunks(new_l) - length(Bc)
33,521✔
1018
    delta_k < 0 && _deleteend!(Bc, -delta_k)
33,521✔
1019

1020
    B.len = new_l
33,521✔
1021

1022
    if new_l > 0
33,521✔
1023
        Bc[end] &= _msk_end(new_l)
33,521✔
1024
    end
1025

1026
    return B
33,521✔
1027
end
1028

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

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

1036
    Bc = B.chunks
3,809✔
1037

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

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

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

1061
    B.len = new_l
3,809✔
1062

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

1067
    return B
3,809✔
1068
end
1069

1070
keepat!(B::BitVector, inds) = _keepat!(B, inds)
2✔
1071
keepat!(B::BitVector, inds::AbstractVector{Bool}) = _keepat!(B, inds)
×
1072

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

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

1087
const _default_bit_splice = BitVector()
1088

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

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

1100
    Bins = convert(BitArray, ins)
74,706✔
1101

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

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

1109
    Bc = B.chunks
74,670✔
1110

1111
    lins = length(Bins)
74,670✔
1112
    ldel = length(r)
74,670✔
1113

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

1117
    delta_k > 0 && _growend!(Bc, delta_k)
74,670✔
1118

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

1122
    delta_k < 0 && _deleteend!(Bc, -delta_k)
74,670✔
1123

1124
    B.len = new_l
74,670✔
1125

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

1130
    return v
74,670✔
1131
end
1132

1133
function splice!(B::BitVector, r::Union{AbstractUnitRange{Int}, Integer}, ins)
12,552✔
1134
    Bins = BitVector(undef, length(ins))
12,552✔
1135
    i = 1
12,552✔
1136
    for x in ins
25,104✔
1137
        Bins[i] = Bool(x)
1,340,140✔
1138
        i += 1
1,340,140✔
1139
    end
2,680,280✔
1140
    return splice!(B, r, Bins)
12,552✔
1141
end
1142

1143

1144
function empty!(B::BitVector)
4,179✔
1145
    _deleteend!(B.chunks, length(B.chunks))
4,179✔
1146
    B.len = 0
4,179✔
1147
    return B
4,179✔
1148
end
1149

1150
## Unary operators ##
1151

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

1181
## Binary arithmetic operators ##
1182

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

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

1207
## promotion to complex ##
1208

1209
# TODO?
1210

1211
## comparison operators ##
1212

1213
function (==)(A::BitArray, B::BitArray)
4,020✔
1214
    size(A) != size(B) && return false
9,798✔
1215
    return A.chunks == B.chunks
4,900✔
1216
end
1217

1218

1219
## Data movement ##
1220

1221
# TODO some of this could be optimized
1222

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

1230
    B = similar(A)
4✔
1231

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

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

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

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

1285
    n = length(B)
×
1286
    n == 0 && return B
×
1287

1288
    k = _mod64(n+63) + 1
×
1289
    h = 64 - k
×
1290

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

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

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

1321
    return B
×
1322
end
1323

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

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

1340
"""
1341
    >>(B::BitVector, n) -> BitVector
1342

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

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

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

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

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

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

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

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

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

1415
"""
1416
    >>>(B::BitVector, n) -> BitVector
1417

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

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

1442
circshift!(B::BitVector, i::Integer) = circshift!(B, B, i)
16✔
1443

1444
## count & find ##
1445

1446
function bitcount(Bc::Vector{UInt64}; init::T=0) where {T}
49,347,738✔
1447
    n::T = init
671✔
1448
    @inbounds for i = 1:length(Bc)
78,014,361✔
1449
        n = (n + count_ones(Bc[i])) % T
34,928,436✔
1450
    end
38,059,007✔
1451
    return n
46,216,496✔
1452
end
1453

1454
_count(::typeof(identity), B::BitArray, ::Colon, init) = bitcount(B.chunks; init)
76,115✔
1455

1456
function unsafe_bitfindnext(Bc::Vector{UInt64}, start::Int)
25,565,397✔
1457
    chunk_start = _div64(start-1)+1
25,565,397✔
1458
    within_chunk_start = _mod64(start-1)
25,565,397✔
1459
    mask = _msk64 << within_chunk_start
25,565,397✔
1460

1461
    @inbounds begin
×
1462
        if Bc[chunk_start] & mask != 0
25,565,397✔
1463
            return (chunk_start-1) << 6 + trailing_zeros(Bc[chunk_start] & mask) + 1
18,591,443✔
1464
        end
1465

1466
        for i = chunk_start+1:length(Bc)
8,384,965✔
1467
            if Bc[i] != 0
5,167,912✔
1468
                return (i-1) << 6 + trailing_zeros(Bc[i]) + 1
1,399,079✔
1469
            end
1470
        end
7,525,734✔
1471
    end
1472
    return nothing
5,574,875✔
1473
end
1474

1475
# returns the index of the next true element, or nothing if all false
1476
function findnext(B::BitArray, start::Integer)
57,878✔
1477
    start = Int(start)
19✔
1478
    start > 0 || throw(BoundsError(B, start))
57,880✔
1479
    start > length(B) && return nothing
60,941✔
1480
    unsafe_bitfindnext(B.chunks, start)
59,928✔
1481
end
1482

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

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

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

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

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

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

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

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

1542
function unsafe_bitfindprev(Bc::Vector{UInt64}, start::Int)
31,976✔
1543
    chunk_start = _div64(start-1)+1
31,976✔
1544
    mask = _msk_end(start)
31,976✔
1545

1546
    @inbounds begin
×
1547
        if Bc[chunk_start] & mask != 0
31,976✔
1548
            return (chunk_start-1) << 6 + (top_set_bit(Bc[chunk_start] & mask))
28,391✔
1549
        end
1550

1551
        for i = (chunk_start-1):-1:1
7,164✔
1552
            if Bc[i] != 0
4,728✔
1553
                return (i-1) << 6 + (top_set_bit(Bc[i]))
3,574✔
1554
            end
1555
        end
2,303✔
1556
    end
1557
    return nothing
11✔
1558
end
1559

1560
# returns the index of the previous true element, or nothing if all false
1561
function findprev(B::BitArray, start::Integer)
13,159✔
1562
    start = Int(start)
21✔
1563
    start > 0 || return nothing
13,283✔
1564
    start > length(B) && throw(BoundsError(B, start))
13,281✔
1565
    unsafe_bitfindprev(B.chunks, start)
13,279✔
1566
end
1567

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

1573
    Bc = B.chunks
21,223✔
1574

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

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

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

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

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

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

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

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

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

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

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

1672
@inline _overflowind(i1, irest::Tuple{}, size) = (i1, irest)
5,620✔
1673
@inline function _overflowind(i1, irest, size)
3,487✔
1674
    i2 = irest[1]
3,487✔
1675
    while i1 > size[1]
5,408✔
1676
        i1 -= size[1]
1,921✔
1677
        i2 += 1
1,921✔
1678
    end
1,921✔
1679
    i2, irest = _overflowind(i2, tail(irest), tail(size))
3,487✔
1680
    return (i1, (i2, irest...))
3,487✔
1681
end
1682

1683
@inline _toind(i1, irest::Tuple{}) = i1
×
1684
@inline _toind(i1, irest) = CartesianIndex(i1, irest...)
1,141✔
1685

1686
function findall(B::BitArray)
1,359✔
1687
    nnzB = count(B)
3,503✔
1688
    I = Vector{eltype(keys(B))}(undef, nnzB)
1,359✔
1689
    nnzB == 0 && return I
1,359✔
1690
    nnzB == length(B) && (allindices!(I, B); return I)
1,674✔
1691
    Bc = B.chunks
692✔
1692
    Bs = size(B)
45✔
1693
    Bi = i1 = i = 1
45✔
1694
    irest = ntuple(one, ndims(B) - 1)
45✔
1695
    c = Bc[1]
692✔
1696
    @inbounds while true
20,607✔
1697
        while c == 0
23,054✔
1698
            Bi == length(Bc) && return I
2,023✔
1699
            i1 += 64
1,331✔
1700
            Bi += 1
1,331✔
1701
            c = Bc[Bi]
1,331✔
1702
        end
1,331✔
1703

1704
        tz = trailing_zeros(c)
21,056✔
1705
        c = _blsr(c)
21,056✔
1706

1707
        i1, irest = _overflowind(i1 + tz, irest, Bs)
21,056✔
1708
        I[i] = _toind(i1, irest)
21,056✔
1709
        i += 1
21,056✔
1710
        i1 -= tz
21,056✔
1711
    end
21,056✔
1712
end
1713

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

1717
## Reductions ##
1718

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

1722
function all(B::BitArray)
396✔
1723
    isempty(B) && return true
627✔
1724
    Bc = B.chunks
625✔
1725
    @inbounds begin
201✔
1726
        for i = 1:length(Bc)-1
644✔
1727
            Bc[i] == _msk64 || return false
148✔
1728
        end
268✔
1729
        Bc[end] == _msk_end(B) || return false
737✔
1730
    end
1731
    return true
507✔
1732
end
1733

1734
function any(B::BitArray)
9,395✔
1735
    isempty(B) && return false
3,171,912✔
1736
    Bc = B.chunks
3,171,911✔
1737
    @inbounds begin
1,543✔
1738
        for i = 1:length(Bc)
6,343,822✔
1739
            Bc[i] == 0 || return true
6,338,687✔
1740
        end
5,933✔
1741
    end
1742
    return false
5,401✔
1743
end
1744

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

1748
## map over bitarrays ##
1749

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

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

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

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

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

1821
## Filter ##
1822

1823
function filter(f, Bs::BitArray)
×
1824
    boolmap::Array{Bool} = map(f, Bs)
×
1825
    Bs[boolmap]
×
1826
end
1827

1828

1829
## Concatenation ##
1830

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

1844
function vcat(V::BitVector...)
323✔
1845
    n = 0
323✔
1846
    for Vk in V
323✔
1847
        n += length(Vk)
694✔
1848
    end
1,017✔
1849
    B = BitVector(undef, n)
323✔
1850
    j = 1
323✔
1851
    for Vk in V
323✔
1852
        copy_chunks!(B.chunks, j, Vk.chunks, 1, length(Vk))
694✔
1853
        j += length(Vk)
694✔
1854
    end
1,017✔
1855
    return B
323✔
1856
end
1857

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

1871
    B = BitMatrix(undef, nrows, ncols)
1✔
1872

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

1883
function vcat(A::BitMatrix...)
38✔
1884
    nargs = length(A)
38✔
1885
    nrows, nrowsA = 0, sizehint!(Int[], nargs)
38✔
1886
    for a in A
38✔
1887
        sz1 = size(a, 1)
198✔
1888
        nrows += sz1
198✔
1889
        push!(nrowsA, sz1)
198✔
1890
    end
236✔
1891
    ncols = size(A[1], 2)
38✔
1892
    for j = 2:nargs
72✔
1893
        size(A[j], 2) == ncols ||
161✔
1894
        throw(DimensionMismatch("column lengths must match: $j-th element has second dim $(size(A[j], 2)), should have $ncols"))
1895
    end
281✔
1896
    B = BitMatrix(undef, nrows, ncols)
37✔
1897
    Bc = B.chunks
37✔
1898
    pos_d = 1
37✔
1899
    pos_s = fill(1, nargs)
195✔
1900
    for j = 1:ncols, k = 1:nargs
195✔
1901
        copy_chunks!(Bc, pos_d, A[k].chunks, pos_s[k], nrowsA[k])
1,620✔
1902
        pos_s[k] += nrowsA[k]
1,620✔
1903
        pos_d += nrowsA[k]
1,620✔
1904
    end
1,762✔
1905
    return B
37✔
1906
end
1907

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

1918
# hvcat -> use fallbacks in abstractarray.jl
1919

1920

1921
# BitArray I/O
1922

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

1935
sizeof(B::BitArray) = sizeof(B.chunks)
2✔
1936

1937
function _split_rest(a::Union{Vector, BitVector}, n::Int)
6✔
1938
    _check_length_split_rest(length(a), n)
6✔
1939
    last_n = a[end-n+1:end]
5✔
1940
    resize!(a, length(a) - n)
10✔
1941
    return a, last_n
5✔
1942
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