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
- 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
julia> struct DummyHeader
julia> reinterpret(DummyHeader, read(buf, sizeof(DummyHeader)))
DummyHeader(1, FEAT_ACTIVE | FEAT_READ | FEAT_BACKUP::DummyFeatures = 0x0000000b, 100)
Hopefully others can derive some utility from this simple package.
Cool. Should be coming to Base sometime too: https://github.com/JuliaLang/julia/pull/19470
Ah, interesting! I’d tried searching for such a feature last weekend and apparently never came up with the right search query to bring up that PR.
Hi. Thanks! This is really helpful.
I found one behavior of the code which I don’t know if is expected: the bitwise and operation between two constants cuases an error. For example:
@bitflag flag begin
[ sorry, I pressed ‘Reply’ too early by error]
f1 & f2 # causes an error
g = f1 | f2
g & f1 #causes error
And this is important to check if the flag is present or not. I believe the zero flag should be permitted
If you explicitly permit a zero-valued item, then it works without type conversions:
julia> using BitFlags
julia> @bitflag flag begin
fnone = 0
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)
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.
Great! That indeed solves the problem. Thank you very much.