1

I work on a project with many bitwise option sets and each of them contains many options with all option e.g:

struct MyOption: OptionSet {
    let rawValue: Int
    
    static let a = Self(rawValue: 1 << 0)
    static let b = Self(rawValue: 1 << 1)
    static let c = Self(rawValue: 1 << 2)
    ...
    static let last = Self(rawValue: 1 << N)
    
    static let all: Self = [.a, .b, .c, ..., .last]
}

It requires to maintain much of similar code so is it any way to eliminate hardcoded bitwise shift operations and the all option?

iUrii
  • 11,742
  • 1
  • 33
  • 48

1 Answers1

3

You can use next OptionSet's extension which implements all option and a convenient initializer:

extension OptionSet where RawValue == Int {
    static var all: Self {
        Self.init(rawValue: Int.max)
    }
    
    init(_ shift: Int) {
        self.init(rawValue: 1 << shift)
    }
}

Then you can re-write your option set:

struct Option: OptionSet {
    let rawValue: Int
    
    static let a = Self(0)
    static let b = Self(1)
    static let c = Self(2)
}

Option.a.rawValue // 1
Option.b.rawValue // 2
Option.c.rawValue // 4

let options: Option = [.a, .b]
Option.all.contains(options) // true
iUrii
  • 11,742
  • 1
  • 33
  • 48
  • 2
    I like that solution (voted), although I would suggest using a named parameter for your `init(shift:)` initializer, since it would be easy to think it takes values rather than bit positions. Maybe even name it `init(bitIndex:)`. – Duncan C Jul 21 '21 at 15:50
  • 1
    I wonder if there is any potential problem using a raw value of Int.max, which will have bit values set that are not defined for most OptionSets (Since very few OptionSets will have 64 different flags) – Duncan C Jul 21 '21 at 15:53
  • I think the problem is an interesting one but I don't see how this answer improves anything. – matt Jul 21 '21 at 15:53