Last active
September 22, 2018 00:35
-
-
Save mlaster/4ac383be6d254cc185fb80b72bceb85c to your computer and use it in GitHub Desktop.
Attempt at enumerable OptionSet
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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