Skip to content

Instantly share code, notes, and snippets.

@wildthink
Last active October 27, 2017 16:45
Show Gist options
  • Save wildthink/4ba82cb7ee3d0c1fdfe4874567ca3300 to your computer and use it in GitHub Desktop.
Save wildthink/4ba82cb7ee3d0c1fdfe4874567ca3300 to your computer and use it in GitHub Desktop.
Swift Integer enum sequence
// Distilation of ideas and examples from these great contributions to the community
// http://stackoverflow.com/questions/24007461/how-to-enumerate-an-enum-with-string-type
// https://forums.developer.apple.com/thread/4404
// https://www.natashatherobot.com/swift-conform-to-sequence-protocol/
// https://theswiftdev.com/2017/10/12/swift-enum-all-values/
import Foundation
public protocol EnumCollection: Hashable {
static func cases() -> AnySequence<Self>
static var allValues: [Self] { get }
}
public extension EnumCollection {
public static func cases() -> AnySequence<Self> {
return AnySequence { () -> AnyIterator<Self> in
var raw = 0
return AnyIterator {
let current: Self = withUnsafePointer(to: &raw) { $0.withMemoryRebound(to: self, capacity: 1) { $0.pointee } }
guard current.hashValue == raw else {
return nil
}
raw += 1
return current
}
}
}
public var enumIndex: Int {
var ndx: Int = 0
for c in Self.cases() {
if c.hashValue == self.hashValue { return ndx }
ndx += 1
}
return -1
}
public static var allValues: [Self] {
return Array(self.cases())
}
public init? (index: Int) {
for (ndx, c) in Self.cases().enumerated() {
if ndx == index {
self = c
return
}
}
return nil
}
}
// Enumerator OptionSets
// https://stackoverflow.com/questions/32102936/how-do-you-enumerate-optionsettype-in-swift
// 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
}
}
}
}
/* Older approach - prefer the one above
protocol IntegerEnum {
init? (rawValue: Int)
static var firstRawValue: Int { get }
}
extension IntegerEnum {
static var firstRawValue: Int { return 0 }
static var sequence: AnyGenerator<Self> {
var lastIteration = firstRawValue
return AnyGenerator {
lastIteration += 1
return Self(rawValue: lastIteration - 1)
}
}
}
enum Suit: Int, IntegerEnum {
case Hearts, Clubs, Diamonds, Spades
}
enum Size: Int, IntegerEnum {
case Small, Medium, Large
}
for s in Suit.sequence {
print (s)
}
for s in Size.sequence {
print (s)
}
let a = Array(Suit.sequence) // [Hearts, Clubs, Diamonds, Spades]
Size.sequence.reverse() // [Large, Medium, Small]
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment