Skip to content

Instantly share code, notes, and snippets.

@mlaster
Last active September 22, 2018 00:35
Show Gist options
  • Save mlaster/4ac383be6d254cc185fb80b72bceb85c to your computer and use it in GitHub Desktop.
Save mlaster/4ac383be6d254cc185fb80b72bceb85c to your computer and use it in GitHub Desktop.
Attempt at enumerable OptionSet
// FIXME: How do a genericize this to work with any UInt* type?
public struct OptionSetIterator<Element: OptionSet>: IteratorProtocol where Element.RawValue == UInt16 {
private let value: Element
public init(element: Element) {
self.value = element
}
private lazy var remainingBits = value.rawValue
private var bitMask: Element.RawValue = 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
}
}
//extension OptionSet where Self.RawValue == Int16 {
// public func makeIterator() -> OptionSetIterator<Self> {
// return OptionSetIterator(element: self)
// }
//}
public struct Capabilities: OptionSet, Sequence {
public typealias Storage = UInt16
public let rawValue: Storage
public static let one = Capabilities(.one)
public static let two = Capabilities(.two)
public static let three = Capabilities(.three)
public static let four = Capabilities(.four)
public static let five = Capabilities(.five)
public static let six = Capabilities(.six)
public static let seven = Capabilities(.seven)
public static let eight = Capabilities(.eight)
public func makeIterator() -> OptionSetIterator<Capabilities> {
return OptionSetIterator(element: self)
}
// FIXME: And get rid of this embedded enum hack?
public enum Capability: String, CaseIterable {
case one
case two
case three
case four
case five
case six
case seven
case eight
static var rawValueMap: [Capability: Storage] = {
var dict: [Capability: Storage] = [:]
for (index, capability) in Capability.allCases.enumerated() {
assert(index < MemoryLayout<Storage>.size * 8, "Not enough bits for index \(index)")
dict[capability] = 1 << index
}
return dict
}()
static var reverseMap: [Int: Capability] = {
var dict: [Int: Capability] = [:]
for (index, capability) in Capability.allCases.enumerated() {
assert(index < MemoryLayout<Storage>.size * 8, "Not enough bits for index \(index)")
dict[index] = capability
}
return dict
}()
var shift: Storage {
guard let value = Capability.rawValueMap[self] else { fatalError("Unmapped capability: \(self)!")}
return value
}
var capabilityLabel: String { return rawValue }
}
public init(rawValue: RawValue) {
self.rawValue = rawValue
}
private init (_ capability: Capability) {
self.rawValue = capability.shift
}
}
extension Capabilities: CustomStringConvertible {
public var description: String {
var capabilities = [String]()
var workRaw = rawValue
var column = 0
while workRaw != 0 {
let lsb = workRaw & 1
if lsb != 0 {
if let capability = Capability.reverseMap[column] {
capabilities.append(".\(capability.capabilityLabel)")
}
}
workRaw >>= 1
column += 1
}
return "[\(capabilities.joined(separator: ", "))]"
}
}
let c = Capabilities([.one, .three, .five])
print("c is \(c)")
for e in c {
print("e is \(e)")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment