I’d like to announce BitFlags.jl, a package that provides an @enum-like macro that constructs types tailored for use with bit flags. It’s largely a borrowing of the Enum code with minor modifications, so almost all the credit goes to everyone who worked on the Base implementation. What it provides on top of a regular Enum is:
Automatic power-of-two numbering, and enforcement that members are a power of two
Binary AND (&) and OR (|) operations are defined
Pretty-printing of values as combinations of members
For example, my motivation was to make data structures dumped from memory easier to introspect — e.g.
julia> # Setup dummy data — could be file instead
julia> buf = IOBuffer(); write(buf, Int32(1), UInt32(11), Int64(100)); seekstart(buf);
julia> using BitFlags
julia> @bitflag DummyFeatures::UInt32 begin
FEAT_ACTIVE
FEAT_READ
FEAT_WRITE
FEAT_BACKUP
FEAT_SHARED
end
julia> struct DummyHeader
version::Int32
features::DummyFeatures
payload_size::Int64
end
julia> reinterpret(DummyHeader, read(buf, sizeof(DummyHeader)))[1]
DummyHeader(1, FEAT_ACTIVE | FEAT_READ | FEAT_BACKUP::DummyFeatures = 0x0000000b, 100)
Hopefully others can derive some utility from this simple package.
If you explicitly permit a zero-valued item, then it works without type conversions:
julia> using BitFlags
julia> @bitflag flag begin
f1
f2
f3
fnone = 0
end
julia> f1 & f2
fnone::flag = 0x00000000
(I don’t see an error in the second case you gave — did you mean to do g & f3?
This behavior was specifically chosen because you may want to enforce at least one flag bit being set for any given realization/instantiation of the bit falgs. You can also cast to regular integers to compare to zero:
julia> Int(g) & Int(f3)
0
I debated with myself on exactly how to handle this case, and I figured allowing explicitly-zero flags in the definition was a reasonable solution.