Swift bitfield enums

Enums and bitfields

Swift is a great language, the generics are great and only few things really bother me but, hey, it's still a very young language compared to Objective-C or C for that matter.

For instance, I was used to declaring enums (the old way, not even with the NS_ENUM macro) but now in swift where the enums are "premium" citizens let's see what we can do ;)


enum UpdateState: UInt {
  case None = 0
  case ShouldRegulateSpeeds = 1 << 0
  case RegulatesSpeeds = 1 << 1
  case ShouldScrambleSpeeds = 1 << 2 
}

The first thing that stroke me was the compiler with an error stating that it needs literal values... the shifted values don't work anymore :/, but hopefuly I know how to count 2^n:


enum UpdateState: UInt {
  case None = 0
  case ShouldRegulateSpeeds = 1
  case RegulatesSpeeds = 2
  case ShouldScrambleSpeeds = 4 
}

Now, I thought I could add methods to the enum to check whether a bit is set, etc, but the thing is that it's not possible for the compiler to know if a OR a XOR, a AND or any other bitwize operation on any of the predefined bits will result in a value that is part of the defined type set. For example let's try to add ShouldRegulateSpeeds and ShouldScrambleSpeeds:

var state: UpdateState = .ShouldRegulateSpeeds | .ShouldScrambleSpeeds

The enum Type "UpdateState" which inherits from UInt is an enum Type. To access the raw value, you need to access the rawValue of the instance.

var state: UpdateState = .ShouldRegulateSpeeds.rawValue | .ShouldScrambleSpeeds.rawValue

But even then, the bitwize operation will not result in a UpdateState value (two raw values ORed) so the compiler throws an error.

The thing is, we are trying to mix two different things here:

1) The predefined values also known as the bits

2) The association of one or more of these values also known as the field

In order to solve this we need to have two different types, one for the enum and one for the compound value. A struct will do.


enum UpdateState: UInt {
  case None = 0
  case ShouldRegulateSpeeds = 1
  case RegulatesSpeeds = 2
  case ShouldScrambleSpeeds = 4 
}

struct UpdateStateField {
  var value: UInt
  init(_ state: UpdateState) {
    value = state.rawValue
  }
}

var updateState = UpdateStateField(.None)

Youpi! It works. Of course we could add more candies to the struct like a has(bits: UpdateState) method and more to set/unset bits etc...

Next, we want to use generics, not because it's hype... but because it will help us get a reusable pattern for this bitfield problem. Something like:

struct BitField<T,V> {
  var value: V
  init(_ state: T) {
    value = state.rawValue
  }
}

var updateState = BitField<UpdateState,UInt>(.None)

The first problem with this, is that we need two types when we could certainly infer the second from the first. Also, there is a probleme because we need to call rawValue on a type T which we don't know if it allows this call.

Generic Protocols

Swift is built from the ground up with a lot of generic protocols which is very convenient. To discover the protocols you can add a swift import like this:

import Swift

Then in Xcode, Command-Click on the "Swift" word on the import line, it will lead you to the Swift header. It is very instructive to read this header. For example seach the word "RawRepresentable" and there you go, the protocol is explained there:

protocol RawRepresentable {
    typealias RawValue
    init?(rawValue: RawValue)
    var rawValue: RawValue { get }
}

There is one important thing to note here: the typealias. This alias allows one to reuse this protocol in a type definition. We want our type T (remember the definition of the BitField struct) to be a descendant of RawRepresentable so we can call .rawValue on any object of type T. Which translates to:

struct BitField<T: RawRepresentable, V> {
  var value: V
  init(_ state: T) {
    value = state.rawValue
  }
}

And as I told you, we could infer the type of the value var from T since T needs to return a rawValue of this very type. That's where the RawRepresentable.RawValue comes in handy:

struct BitField<T: RawRepresentable> {
  var value: T.RawValue
  init(_ state: T) {
    value = state.rawValue
  }
}

Now we can store a combination of the enum values in this struct like this:

var state = BitField<UpdateState>(.None)

But I can ear you saying we did not use a compound value at this point... right! You may use the state.value var to specify a compound value but a better solution could be to add an initializer that takes a list of enum values and OR them all:

init(_ states: T...) {
  value = 0
  for state in states {
    value |= state.rawValue
  }
}

Now we can add multiple UpdateState values:

var state = BitField<UpdateState>(.ShouldScrambleSpeeds, .ShouldRegulateSpeeds)

Wait! It's not working anymore because we introduced a bitwize operation in the mix. We need to specify to the compiler that not only T conforms to RawRepresentable but also that the BitField value which is of type T.RawValue conforms to BitwiseOperationsType, an other protocol that allows one to add bitwize functionalities to a type. And while we are doing it, we should also add Comparable and IntegerLiteralConvertible protocols as requirements for T.RawValue. How do we do that? With the where clause in the type definition:

struct BitField<T: RawRepresentable where T.RawValue: Comparable, 
                                          T.RawValue: BitwiseOperationsType, 
                                          T.RawValue: IntegerLiteralConvertible> {
  var value: T.RawValue = 0
  init(_ states: T...) {
    for state in states {
      value |= state.rawValue
    }
  }
  func has(state: T) -> Bool {
    return value & state.rawValue != 0
  }

}

Now if we add a set() and a unset() method we are good to go. Here is my personal implementation of this BitField:


struct BitField<U: RawRepresentable where U.RawValue: Comparable, 
                                          U.RawValue: BitwiseOperationsType, 
                                          U.RawValue: IntegerLiteralConvertible> {
  var value: U.RawValue = 0

  init(_ state: U) { reset([state]) }
  init(_ states: U...) { reset(states) }

  func has(state: U) -> Bool { return has([state]) }
  func has(states: U ...) -> Bool { return has(states) }
  func has(states: [U]) -> Bool {
    for state in states {
      if value & state.rawValue == 0 { return false }
    }
    return true
  }

  mutating func set(states: U...) { set(states) }
  mutating func set(state: U) { set([state]) }
  mutating func set(states: [U]) {
    for state in states {
      value |= state.rawValue
    }
  }

  mutating func unset(states: U...) { unset(states) }
  mutating func unset(state: U) { unset([state]) }
  mutating func unset(states: [U]) {
    for state in states {
      if !has([state]) { continue }
      value ^= state.rawValue
    }
  }

  mutating func reset(states: U...) { reset(states) }
  mutating func reset(state: U) { reset([state]) }
  mutating func reset(states: [U]) {
    value = 0
    for state in states {
      value |= state.rawValue
    }
  }
}

Note that since for a reason I cannot explain swift compiler cannot infer the type T from an argument of type T... (meaning variadic argument of type T) when only one argument was provided I had to overload all functions to take one or more arguments. I hope it will get fixed at some point in the future.

Example usage:

enum Fruits: Int {
  case None = 0
  case Orange = 1
  case Banana = 2
  case Lemon = 4
  case Strawberry = 8
}

var myFruits = BitField<Fruits>(.Orange, .Lemon)  #=> {value 5} 
myFruits.has(.Banana)                             #=> false
myFruits.has(.Lemon)                              #=> true
myFruits.has(.Orange)                             #=> true
myFruits.set(.Banana)                             #=> {value 7}
myFruits.unset(.Lemon)                            #=> {value 3}
myFruits.has(.Lemon)                              #=> false
myFruits.set(.Strawberry, .Lemon)                 #=> {value 15}

Cheers