Lightweight package with zero dependencies aimed at manipulating BitMasks using an @enum
like interface. BitMasks are combinations of boolean flags encoded as specific bits of an integer type. For example, 8 flags can be represented with a UInt8
, from 0b1000000
to 0b00000001
. A bitmask instance could then have a value of 0b10101101
in this case.
This package provides a way to define BitMasks from flag values and mask presets, and operators to manipulate them. First, you can create a bitmask type with
julia> using BitMasks
julia> @bitmask Mask::UInt32 begin
# Flags.
BIT_A = 1
BIT_B = 2
BIT_C = 4
# Mask presets.
BIT_AB = BIT_A | BIT_B
BIT_BC = BIT_B | BIT_C
BIT_ABC = BIT_A | BIT_B | BIT_C
end
Mask
Mask presets are optional, but can be handy to group parameters especially when specific masks have a strong semantic meaning or when the number of flags is very large. The right-hand sides of the =
assignments are required to be integer literals at the moment.
It is also possible to combine flags or masks to create new masks, for example
julia> BIT_A | BIT_C
Mask(BIT_A | BIT_C)
julia> BIT_A | BIT_B
Mask(BIT_AB)
julia> ~BIT_A
Mask(BIT_BC)
julia> BIT_BC ⊻ BIT_AB
Mask(BIT_A | BIT_C)
julia> BIT_BC & BIT_C
Mask(BIT_C)
where |
performs the union of different flags or masks, &
their intersection, ~
their complement and xor
the complement of their intersection. Note that |
should be read as and
instead of or
from a semantic perspective.
You will have noticed that a specific printing is defined which will try to compact all combinations based on the provided presets to reduce verbosity.
If you need access to the underlying integer value, you can use convert any BitMask
to an Integer
:
julia> convert(Integer, BIT_C)
0x00000004
Other utilities are defined, such as the extraction of all flags from a mask, conversion to/from integers and bits of extra type safety to avoid mixing flags coming from different masks:
julia> enabled_flags(BIT_ABC)
3-element Vector{Mask}:
Mask(BIT_A)
Mask(BIT_B)
Mask(BIT_C)
julia> Int(BIT_A)
1
julia> Mask(1)
Mask(BIT_A)
julia> @bitmask Mask2::UInt32 begin
BIT_A_2 = 1
BIT_B_2 = 2
BIT_AB_2 = BIT_A_2 | BIT_B_2
end
Mask2
julia> BIT_A | BIT_B_2
ERROR: Bitwise operation not allowed between incompatible BitMasks 'Mask', 'Mask2'
Finally, a few common Base
methods were added for convenience:
julia> zero(Mask)
Mask()
julia> iszero(zero(Mask))
true
julia> typemax(Mask)
Mask(BIT_ABC)
You can also choose to export all defined symbols (and the defined type) with the parameter export = true
(which is false
by default):
@bitmask exported = true Mask3::UInt32 begin
BIT_A_3 = 1
BIT_B_3 = 2
BIT_AB_3 = BIT_A_3 | BIT_B_3
end
This package aims to be relatively simple and designed to work with integers only. Similar packages with slightly different feature sets include: