If you decide to go with a vector of UInts, here is how you can treat a single UInt like a BitVector:

```
julia> struct SBitVector <: AbstractVector{Bool}
x::UInt
len::Int
end
julia> Base.size(v::SBitVector) = (v.len,)
julia> Base.@propagate_inbounds function Base.getindex(v::SBitVector, i::Int)
Base.@boundscheck 1 <= i <= length(v)
return (v.x >> (i-1)) % Bool
end
julia> Base.@propagate_inbounds function Base.setindex(v::SBitVector, i::Int, x::Bool)
Base.@boundscheck 1 <= i <= length(v) || throw(BoundsError(v, i))
mask = UInt(1) << (i-1)
res = ifelse(x, v.x | mask, v.x & ~mask)
return SBitVector(res, v.len)
end
julia> v = SBitVector(rand(UInt8), 8)
8-element SBitVector:
0
1
1
0
1
0
0
0
julia> v[3]
true
julia> Base.setindex(v, 3, false)
8-element SBitVector:
0
1
0
0
1
0
0
0
```

You could then just make a vector of `SBitVector`

s.

Edit:

Probably more efficient in most cases, if the length is a type parameter:

```
julia> struct SBitVector{len} <: AbstractVector{Bool}
x::UInt
end
julia> Base.size(v::SBitVector{len}) where {len} = (len,)
julia> Base.@propagate_inbounds function Base.getindex(v::SBitVector, i::Int)
Base.@boundscheck 1 <= i <= length(v) || throw(BoundsError(v, i))
return (v.x >> (i-1)) % Bool
end
julia> Base.@propagate_inbounds function Base.setindex(v::SBitVector{len}, i::Int, x::Bool) where {len}
Base.@boundscheck 1 <= i <= length(v) || throw(BoundsError(v, i))
mask = UInt(1) << (i-1)
res = ifelse(x, v.x | mask, v.x & ~mask)
return SBitVector{len}(res)
end
julia> v = SBitVector{8}(rand(UInt8))
8-element SBitVector{8}:
0
1
1
1
0
0
1
1
julia> v[3]
true
julia> Base.setindex(v, 3, false)
8-element SBitVector{8}:
0
1
0
1
0
0
1
1
```