Last active
October 27, 2017 16:45
-
-
Save wildthink/4ba82cb7ee3d0c1fdfe4874567ca3300 to your computer and use it in GitHub Desktop.
Swift Integer enum sequence
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
// 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