BitOps for Julia
"""
BitOps exports functions using low level bit manipulation to modify standard Int and UInt values.
Note: Functions that check their arguments are named `safe_..`, others do no checking.
Copyright 2017 by Jeffrey Sarnoff. Released under the MIT License.
"""
module BitOps
using Compat
export bitsizeof, clr_bit, set_bit, flp_bit,
iso_bit, get_bit, put_bit,
clr_lsbits, set_lsbits, clr_msbits, set_msbits,
mask_bits, filt_bits
#if VERSION < v"0.6.0-alpha"
# xor(a,b) = a$b
#end
"bit size of type or value"
bitsizeof{T}(::Type{T}) = sizeof(T) << 3
bitsizeof{T}(x::T) = bitsof(T)
const SUN = Union{Signed, Unsigned}
const INT = Union{Int32, Int64} # bit manipulations with Int32 shifts tend to be faster
set_bit{T<:SUN, I<:INT}(::Type{T}, bitidx::I) = one(T) << bitidx
clr_bit{T<:SUN, I<:INT}(::Type{T}, bitidx::I) = ~(one(T) << bitidx)
@compat flp_bit{T<:SUN, I<:INT}(x::T, bitidx::I) = xor(x, set_bit(T, bitidx))
iso_bit{T<:SUN, I<:INT}(x::T, bitidx::I) = x & set_bit(T, bitidx)
get_bit{T<:SUN, I<:INT}(x::T, bitidx::I) = (iso_bit(x, bitidx) >> bitidx) == one(T)
put_bit{T<:SUN, I<:INT}(x::T, bitidx::I, bitvalue::Bool) = (x & clr_bit(T, bitidx)) | (bitvalue << bitidx)
set_lsbits{T<:SUN, I<:INT}(::Type{T}, bitidx::I) = (one(T) << bitidx) - one(T)
clr_lsbits{T<:SUN, I<:INT}(::Type{T}, bitidx::I) = ~((one(T) << bitidx) - one(T))
clr_msbits{T<:SUN, I<:INT}(::Type{T}, bitidx::I) = ~zero(T) >>> bitidx
set_msbits{T<:SUN, I<:INT}(::Type{T}, bitidx::I) = ~(~zero(T) >>> bitidx)
# inclusive of lobitidx and hibitidx
mask_bits{T<:SUN, I<:INT}(::Type{T}, lobitidx::I, hibitidx::I) = set_lsbits(T, hibitidx-lobitidx+1) << lobitidx
filt_bits{T<:SUN, I<:INT}(::Type{T}, lobitidx::I, hibitidx::I) = ~(set_lsbits(T, hibitidx-lobitidx+1) << lobitidx)
set_lsbits{T<:SUN, I<:INT}(x::T, bitidx::I) = x | set_lsbits(T, bitidx)
clr_lsbits{T<:SUN, I<:INT}(x::T, bitidx::I) = x & clr_lsbits(T, bitidx)
set_msbits{T<:SUN, I<:INT}(x::T, bitidx::I) = x | set_msbits(T, bitidx)
clr_msbits{T<:SUN, I<:INT}(x::T, bitidx::I) = x & clr_msbits(T, bitidx)
mask_bits{T<:SUN, I<:INT}(x::T, lobitidx::I, hibitidx::I) = x & mask_bits(T, lobitidx, hibitidx)
filt_bits{T<:SUN, I<:INT}(x::T, lobitidx::I, hibitidx::I) = x & filt_bits(T, lobitidx, hibitidx)
import Base: sign_mask, exponent_mask, significand_mask,
exponent_bits, significand_bits,
(~), (&), (|)
for (U,S) in [(:UInt8, :Int8), (:UInt16, :Int16), (:UInt32, :Int32), (:UInt64, :Int64), (:UInt128, :Int128)]
@eval begin
Base.reinterpret(::Type{Signed}, x::$U) = reinterpret($S, x)
Base.reinterpret(::Type{Signed}, x::$S) = x
Base.reinterpret(::Type{Unsigned}, x::$S) = reinterpret($U, x)
Base.reinterpret(::Type{Unsigned}, x::$U) = x
end
end
end # module BitOps