How do you enumerate OptionSetType in Swift?

I have a custom OptionSetType struct in Swift. How can I enumerate all values of an instance?

This is my OptionSetType:

  • Search for a Regular Expression in Swift 3
  • Updating closures to Swift 3 - @escaping
  • NSImage Getting Resized when I draw Text on it
  • How to convert value of Type 'CBManagerState' to expected type 'CBCentralManagerState' after conversion to Swift 3.0 syntax?
  • Alamofire4 trouble with JSONResponseSerializer & HTTPURLResponse Swift 3.0
  • Swift 3 URLSession.shared() Ambiguous reference to member 'dataTask(with:completionHandler:) error (bug)
  • struct WeekdaySet: OptionSetType {
        let rawValue: UInt8
    
        init(rawValue: UInt8) {
            self.rawValue = rawValue
        }
    
        static let Sunday        = WeekdaySet(rawValue: 1 << 0)
        static let Monday        = WeekdaySet(rawValue: 1 << 1)
        static let Tuesday       = WeekdaySet(rawValue: 1 << 2)
        static let Wednesday     = WeekdaySet(rawValue: 1 << 3)
        static let Thursday      = WeekdaySet(rawValue: 1 << 4)
        static let Friday        = WeekdaySet(rawValue: 1 << 5)
        static let Saturday      = WeekdaySet(rawValue: 1 << 6)
    }
    

    I would like to something like this:

    let weekdays: WeekdaySet = [.Monday, .Tuesday]
    for weekday in weekdays {
        // Do something with weekday
    }
    

    3 Solutions Collect From Internet About “How do you enumerate OptionSetType in Swift?”

    As of Swift 4, there are no methods in the standard library
    to enumerate the elements of an OptionSetType (Swift 2) resp.
    OptionSet (Swift 3, 4).

    Here is a possible implementation which simply checks each bit
    of the underlying raw value, and for each bit which is set,
    the corresponding element is returned.
    The “overflow multiplication” &* 2 is used as left-shift because << is only defined for the concrete integer types, but not for the IntegerType protocol.

    Swift 2.2:

    public extension OptionSetType where RawValue : IntegerType {
    
        func elements() -> AnySequence<Self> {
            var remainingBits = self.rawValue
            var bitMask: RawValue = 1
            return AnySequence {
                return AnyGenerator {
                    while remainingBits != 0 {
                        defer { bitMask = bitMask &* 2 }
                        if remainingBits & bitMask != 0 {
                            remainingBits = remainingBits & ~bitMask
                            return Self(rawValue: bitMask)
                        }
                    }
                    return nil
                }
            }
        }
    }
    

    Example usage:

    let weekdays: WeekdaySet = [.Monday, .Tuesday]
    for weekday in weekdays.elements() {
        print(weekday)
    }
    
    // Output:
    // WeekdaySet(rawValue: 2)
    // WeekdaySet(rawValue: 4)
    

    Swift 3:

    public extension OptionSet where RawValue : Integer {
    
        func elements() -> AnySequence<Self> {
            var remainingBits = rawValue
            var bitMask: RawValue = 1
            return AnySequence {
                return AnyIterator {
                    while remainingBits != 0 {
                        defer { bitMask = bitMask &* 2 }
                        if remainingBits & bitMask != 0 {
                            remainingBits = remainingBits & ~bitMask
                            return Self(rawValue: bitMask)
                        }
                    }
                    return nil
                }
            }
        }
    }
    

    Swift 4:

    public extension OptionSet where RawValue: FixedWidthInteger {
    
        func elements() -> AnySequence<Self> {
            var remainingBits = rawValue
            var bitMask: RawValue = 1
            return AnySequence {
                return AnyIterator {
                    while remainingBits != 0 {
                        defer { bitMask = bitMask &* 2 }
                        if remainingBits & bitMask != 0 {
                            remainingBits = remainingBits & ~bitMask
                            return Self(rawValue: bitMask)
                        }
                    }
                    return nil
                }
            }
        }
    }
    

    Based on the previous answers I created a generic Swift 4 solution with IteratorProtocol:

    public struct OptionSetIterator<Element: OptionSet>: IteratorProtocol where Element.RawValue == Int {
        private let value: Element
    
        public init(element: Element) {
            self.value = element
        }
    
        private lazy var remainingBits = value.rawValue
        private var bitMask = 1
    
        public mutating func next() -> Element? {
            while remainingBits != 0 {
                defer { bitMask = bitMask &* 2 }
                if remainingBits & bitMask != 0 {
                    remainingBits = remainingBits & ~bitMask
                    return Element(rawValue: bitMask)
                }
            }
            return nil
        }
    }
    

    Than in OptionSet extension implement makeIterator()

    assuming your OptionSets will be Int:

    extension OptionSet where Self.RawValue == Int {
       public func makeIterator() -> OptionSetIterator<Self> {
          return OptionSetIterator(element: self)
       }
    }
    

    Right now every time you create an OptionSet, just conform it to Sequence.

    struct WeekdaySet: OptionSet, Sequence {
        let rawValue: Int
    
        ...
    }
    

    You should now be able to iterate over it:

    let weekdays: WeekdaySet = [.monday, .tuesday]
    for weekday in weekdays {
        // Do something with weekday
    }
    

    I’d also create a typealias to be explicit on what is used:

    typealias SequenceOptionSet = OptionSet & Sequence

    Here you go. I also added a convenience initializer to cut down on some of the boilerplate:

    enum Day: Int {
      case Sun, Mon, Tue, Wed, Thu, Fri, Sat
    }
    
    struct WeekdaySet: OptionSetType {
    
      let rawValue: UInt8
    
      init(rawValue: UInt8) {
        self.rawValue = rawValue
      }
    
      init(_ rawValue: UInt8) {
        self.init(rawValue: rawValue)
      }
    
      static let Sunday = WeekdaySet(1 << 0)
      static let Monday = WeekdaySet(1 << 1)
      static let Tuesday = WeekdaySet(1 << 2)
      static let Wednesday = WeekdaySet(1 << 3)
      static let Thursday = WeekdaySet(1 << 4)
      static let Friday = WeekdaySet(1 << 5)
      static let Saturday = WeekdaySet(1 << 6)
      static let AllDays = [Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday]
    
      subscript(indexes: Day...) -> [WeekdaySet] {
        var weekdaySets = [WeekdaySet]()
    
        for i in indexes {
          weekdaySets.append(WeekdaySet.AllDays[i.rawValue])
        }
    
        return weekdaySets
      }
    
    }
    
    for weekday in WeekdaySet()[Day.Mon, Day.Tue] {
      print(weekday)
    }