BitMasks.jl

Manipulating bitmasks with convenience
Author serenity4
Popularity
2 Stars
Updated Last
4 Months Ago
Started In
September 2022

BitMasks

Stable Dev Build Status Coverage ColPrac: Contributor's Guide on Collaborative Practices for Community Packages

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

Related packages

This package aims to be relatively simple and designed to work with integers only. Similar packages with slightly different feature sets include:

Required Packages

No packages found.