JeffreySarnoff
9/9/2017 - 5:42 PM

Nulls as nibble sized bitflag sentinals

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