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
}
}
}
}
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…