Nulls as nibble sized bitflag sentinals
#=
proof of concept
multidimensional indicies are not treated
no comparative benchmarking has been done
=#
module NibbleNulls
export notnull, isnull, setnull!, clearnull!,
NibbleVec
const NibbleVec = Vector{UInt8}
function notnull(nibbles::NibbleVec, index::U) where U<:Unsigned
mask = isodd(index) ? 0x0F : 0xF0
index = index >>> one(U)
@inbounds nibble = getindex(nibbles, index)
nibble = nibble & mask
return nibble === zero(UInt8)
end
@inline function notnull(nibbles::NibbleVec, index::S) where S<:Signed
index >= one(S) && return notnull(nibbles, reinterp(Unsigned, index))
exception_as_false("Illegal index value")
end
function isnull(nibbles::NibbleVec, index::U) where U<:Unsigned
mask = isodd(index) ? 0x0F : 0xF0
index = index >>> one(U)
@inbounds nibble = getindex(nibbles, index)
nibble = nibble & mask
return nibble !== zero(UInt8)
end
@inline function isnull(nibbles::NibbleVec, index::S) where S<:Signed
index >= one(S) && return isnull(nibbles, reinterp(Unsigned, index))
exception_as_false("Illegal index value")
end
function setnull!(nibbles::NibbleVec, index::U) where U<:Unsigned
mask = isodd(index) ? 0x01 : 0x10
index = index >>> one(U)
@inbounds begin
nibble = getindex(nibbles, index)
nibble = nibble | mask
setindex!(nibbles, nibble, index)
end
return nothing
end
@inline function setnull!(nibbles::NibbleVec, index::S) where S<:Signed
index >= one(S) && return setnull!(nibbles, reinterp(Unsigned, index))
exception_as_nothing("Illegal index value")
end
function clearnull!(nibbles::NibbleVec, index::U) where U<:Unsigned
mask = isodd(index) ? 0x10 : 0x01
index = index >>> one(U)
@inbounds begin
nibble = getindex(nibbles, index)
nibble = nibble & mask
setindex!(nibbles, nibble, index)
end
return nothing
end
@inline function clearnull!(nibbles::NibbleVec, index::S) where S<:Signed
!signbit(index - one(S)) && return clearnull!(nibbles, reinterp(Unsigned, index))
exception_as_nothing("Illegal index value")
end
reinterp(::Type{Unsigned}, index::Int8) = reinterpret(UInt8, index)
reinterp(::Type{Unsigned}, index::Int16) = reinterpret(UInt16, index)
reinterp(::Type{Unsigned}, index::Int32) = reinterpret(UInt32, index)
reinterp(::Type{Unsigned}, index::Int64) = reinterpret(UInt64, index)
reinterp(::Type{Unsigned}, index::Int128) = reinterpret(UInt128, index)
# somehow exception(str)::nothing
function exception_as_nothing(str::String)
println(string("*Runtime Exception*:", str))
return nothing
end
end # module