From 5fd95b19435796ea090e9212f03a36a7465927a1 Mon Sep 17 00:00:00 2001 From: oscarddssmith Date: Fri, 3 Jan 2025 17:46:10 -0500 Subject: [PATCH 1/3] reorganize slightly and add FixedSizeBitArray --- src/FixedSizeArrays.jl | 1 + src/FixedSizeBitArray.jl | 78 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 src/FixedSizeBitArray.jl diff --git a/src/FixedSizeArrays.jl b/src/FixedSizeArrays.jl index 44d97b1..2868c4c 100644 --- a/src/FixedSizeArrays.jl +++ b/src/FixedSizeArrays.jl @@ -1,6 +1,7 @@ module FixedSizeArrays include("FixedSizeArray.jl") +include("FixedSizeBitArray.jl") if isdefined(Base, :dataids) && (Base.dataids isa Function) # This is an internal, non-public function which is nevertheless needed to diff --git a/src/FixedSizeBitArray.jl b/src/FixedSizeBitArray.jl new file mode 100644 index 0000000..31f0db2 --- /dev/null +++ b/src/FixedSizeBitArray.jl @@ -0,0 +1,78 @@ +#unlike Base.BitArray, each column gets it's own chunk. +function num_bit_chunks(size::NTuple{N,Int}) where {N} + prod(size[1:end-1]) * ((size[end]+63) >> 6) +end + +struct FixedSizeBitArray{N} <: AbstractArray{Bool,N} + chunks::Memory{UInt64} + size::NTuple{N,Int} + + function FixedSizeBitArray{N}(::Internal, size::NTuple{N,Int}) where {N} + nc = num_bit_chunks(size) + chunks = Memory{UInt64}(undef, nc) + # we want the last chunks to be zerod and it's easier to just zero all of them + copyto!(chunks UInt64(0)) + new{N}(chunks, size) + end +end + +const FixedSizeBitVector = FixedSizeBitArray{1} +const FixedSizeBitMatrix = FixedSizeBitArray{2} + + +function FixedSizeBitArray{N}(::UndefInitializer, size::NTuple{N,Int}) where {N} + checked_dims(size) + FixedSizeBitArray{N}(Internal(), size) +end +function FixedSizeBitArray{N}(::UndefInitializer, size::NTuple{N,Integer}) where {N} + size = map(Int, size)::NTuple{N,Int} # prevent infinite recursion + FixedSizeBitArray{N}(undef, size) +end +function FixedSizeBitArray{N}(::UndefInitializer, size::Vararg{Integer,N}) where {N} + FixedSizeBitArray{N}(undef, size) +end +function FixedSizeBitArray(::UndefInitializer, size::NTuple{N,Integer}) where {N} + FixedSizeBitArray{N}(undef, size) +end +function FixedSizeBitArray(::UndefInitializer, size::Vararg{Integer,N}) where {N} + FixedSizeBitArray{N}(undef, size) +end + +Base.IndexStyle(::Type{<:FixedSizeBitArray}) = IndexCartesian() + +function get_chunks_id(inds::NTuple{N,Int}) where {N} + prod(inds[1:end-1])+(inds[end] >> 6), inds[end] & 63 +end + +Base.@propagate_inbounds function Base.getindex(A::FixedSizeBitArray{N}, inds::Vararg{Int, N}) where {N} + @boundscheck checkbounds(A, inds...) + i1, i2 = get_chunks_id(inds) + u = UInt64(1) << i2 + @inbounds r = (A.chunks[i1] & u) != 0 + return r + +end +Base.@propagate_inbounds Base.@assume_effects :noub_if_noinbounds function Base.setindex!(A::FixedSizeBitArray{N}, x, inds::Vararg{Int, N}) where {N} + @boundscheck checkbounds(A, inds...) + i1, i2 = get_chunks_id(inds) + u = UInt64(1) << i2 + @inbounds begin + c = A.chunks[i1] + A.chunks[i1] = ifelse(x, c | u, c & ~u) + end + return A +end + +Base.size(a::FixedSizeBitArray) = a.size +Base.isassigned(a::FixedSizeBitArray, i::Int) = 1 <= i <= length(a) +function Base.fill!(B::FixedSizeBitArray, x) + y = convert(Bool, x)::Bool + fill!(B.chunks, UInt64(0)-y) + # TODO zero partially filled chunks + return B +end + +function (==)(A::FixedSizeBitArray, B::FixedSizeBitArray) + size(A) != size(B) && return false + return A.chunks == B.chunks +end From 2dbc55d36aefa120c58c8bc105d52e6ca93f2e85 Mon Sep 17 00:00:00 2001 From: Neven Sajko <4944410+nsajko@users.noreply.github.com> Date: Sat, 4 Jan 2025 02:37:48 +0100 Subject: [PATCH 2/3] typo --- src/FixedSizeBitArray.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/FixedSizeBitArray.jl b/src/FixedSizeBitArray.jl index 31f0db2..8fa386c 100644 --- a/src/FixedSizeBitArray.jl +++ b/src/FixedSizeBitArray.jl @@ -10,8 +10,8 @@ struct FixedSizeBitArray{N} <: AbstractArray{Bool,N} function FixedSizeBitArray{N}(::Internal, size::NTuple{N,Int}) where {N} nc = num_bit_chunks(size) chunks = Memory{UInt64}(undef, nc) - # we want the last chunks to be zerod and it's easier to just zero all of them - copyto!(chunks UInt64(0)) + # we want the last chunks to be zeroed and it's easier to just zero all of them + copyto!(chunks, UInt64(0)) new{N}(chunks, size) end end From e00a970f4712bb00905e9f548143ae789295a2d5 Mon Sep 17 00:00:00 2001 From: Neven Sajko <4944410+nsajko@users.noreply.github.com> Date: Sat, 4 Jan 2025 04:22:38 +0100 Subject: [PATCH 3/3] properly add `==` method --- src/FixedSizeBitArray.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FixedSizeBitArray.jl b/src/FixedSizeBitArray.jl index 8fa386c..4eaae6e 100644 --- a/src/FixedSizeBitArray.jl +++ b/src/FixedSizeBitArray.jl @@ -72,7 +72,7 @@ function Base.fill!(B::FixedSizeBitArray, x) return B end -function (==)(A::FixedSizeBitArray, B::FixedSizeBitArray) +function Base.:(==)(A::FixedSizeBitArray, B::FixedSizeBitArray) size(A) != size(B) && return false return A.chunks == B.chunks end