Ben Leggiero Ben Leggiero - 6 days ago 6
Swift Question

How do I convert a bitmask Int into a set of Ints?

I want a function that takes in a bitmask

Int
, and returns its masked values as a set of
Int
s. Something like this:

func split(bitmask: Int) -> Set<Int> {
// Do magic
}


such that

split(bitmask: 0b01001110) == [0b1000000, 0b1000, 0b100, 0b10]

Answer

One solution is to check each bit and add the corresponding mask if the bit is set.

func split(bitmask: Int) -> Set<Int> {
    var results = Set<Int>()

    // Change 31 to 63 or some other appropriate number based on how big your numbers can be        
    for shift in 0...31 {
        let mask = 1 << shift
        if bitmask & mask != 0 {
            results.insert(mask)
        }
    }

    return results
}

print(split(bitmask: 0b01001110))

For the binary number 0b01001110 the results will be:

[64, 2, 4, 8]

which are the decimal equivalent of the results in your question.

For the hex number 0x01001110 (which is 1000100010000 in binary) the results will be:

[16, 256, 4096, 16777216]

Here's another solution that doesn't need to know the size of the value and it's slightly more efficient for smaller numbers:

func split(bitmask: Int) -> Set<Int> {
    var results = Set<Int>()

    var value = bitmask
    var mask = 1
    while value > 0 {
        if value % 2 == 1 {
            results.insert(mask)
        }

        value /= 2
        mask *= 2
    }

    return results
}