Last active
May 12, 2017 01:56
-
-
Save kristopherjohnson/f1cc8baaf0ed0efd326a to your computer and use it in GitHub Desktop.
Helper functions for enumerating values of a Swift enum
This file contains 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
// Protocol for a type that supports a fromRaw(Int) conversion | |
// (such as "enum Foo: Int { ... }") | |
protocol ConvertibleFromRawInt { | |
class func fromRaw(raw: Int) -> Self? | |
} | |
// Note: Tried to use Swift's standard RawRepresentable protocol rather | |
// than ConvertibleFromRawInt, but couldn't get it to compile. | |
// Don't know whether it is a Swift bug or something I was doing wrong. | |
// Generator for a sequence of contiguous ConvertibleFromRawInt values | |
class ConvertibleFromRawIntGenerator<T: ConvertibleFromRawInt>: Generator { | |
typealias Element = T | |
var nextRawValue: Int | |
init(firstRawValue: Int) { | |
nextRawValue = firstRawValue | |
} | |
func next() -> T? { | |
return T.fromRaw(nextRawValue++) | |
} | |
} | |
// Generator for a sequence of ConvertibleFromRawIntValues bounded by low and high raw values | |
class ConvertibleFromRawIntRangeGenerator<T: ConvertibleFromRawInt>: Generator { | |
typealias Element = T | |
var nextRawValue: Int | |
var lastRawValue: Int | |
init(firstRawValue: Int, lastRawValue: Int) { | |
self.nextRawValue = firstRawValue | |
self.lastRawValue = lastRawValue | |
} | |
init(range: Range<Int>) { | |
self.nextRawValue = range.startIndex | |
self.lastRawValue = range.endIndex - 1 | |
} | |
func next() -> T? { | |
if (nextRawValue <= lastRawValue) { | |
return T.fromRaw(nextRawValue++) | |
} | |
else { | |
return nil | |
} | |
} | |
} | |
// Given the first raw value of a ConvertibleFromRawInt type, generate values until fromRaw() returns nil | |
func enumerateFromRawValue<T: ConvertibleFromRawInt>(firstRawValue: Int) -> SequenceOf<T> { | |
return SequenceOf<T>({ ConvertibleFromRawIntGenerator(firstRawValue: firstRawValue) }) | |
} | |
// Given first and last raw values of a range of valid raw values for a ConvertibleFromRawType type, generate a sequence of corresponding values | |
func enumerate<T: ConvertibleFromRawInt>(#firstRawValue: Int, #lastRawValue: Int) -> SequenceOf<T> { | |
return SequenceOf<T>({ ConvertibleFromRawIntRangeGenerator(firstRawValue: firstRawValue, lastRawValue: lastRawValue) }) | |
} | |
// Given a range of valid raw values for a ConvertibleFromRawType type, generate a sequence of corresponding values | |
func enumerate<T: ConvertibleFromRawInt>(#range: Range<Int>) -> SequenceOf<T> { | |
return SequenceOf<T>({ ConvertibleFromRawIntRangeGenerator(range: range) }) | |
} | |
// Examples | |
enum Suit: Int { | |
case Clubs, Diamonds, Hearts, Spades | |
} | |
extension Suit: Printable { | |
var description: String { | |
switch (self) { | |
case .Clubs: return "Clubs" | |
case .Diamonds: return "Diamonds" | |
case .Hearts: return "Hearts" | |
case .Spades: return "Spades" | |
} | |
} | |
} | |
// Enumerate all the suits | |
extension Suit: ConvertibleFromRawInt { | |
static func enumerate() -> SequenceOf<Suit> { | |
return enumerateFromRawValue(Suit.Clubs.toRaw()) | |
} | |
} | |
for suit in Suit.enumerate() { | |
print("\(suit.description) = \(suit.toRaw())\n") | |
} | |
/* Output: | |
Clubs = 0 | |
Diamonds = 1 | |
Hearts = 2 | |
Spades = 3 | |
*/ | |
enum Rank: Int { | |
case Wild = 0 | |
case Two = 2, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King, Ace | |
} | |
extension Rank: Printable { | |
var description: String { | |
switch (self) { | |
case .Two: return "Two" | |
case .Three: return "Three" | |
case .Four: return "Four" | |
case .Five: return "Five" | |
case .Six: return "Six" | |
case .Seven: return "Seven" | |
case .Eight: return "Eight" | |
case .Nine: return "Nine" | |
case .Ten: return "Ten" | |
case .Jack: return "Jack" | |
case .Queen: return "Queen" | |
case .King: return "King" | |
case .Ace: return "Ace" | |
default: return "(Rank \(self.toRaw()))" | |
} | |
} | |
} | |
// Enumerate all the Ranks, skipping over "Wild" | |
extension Rank: ConvertibleFromRawInt { | |
// Enumerate rank values [ Two, Three, ..., King, Ace ] | |
static func enumerate() -> SequenceOf<Rank> { | |
return enumerateFromRawValue(Rank.Two.toRaw()) | |
} | |
} | |
for rank in Rank.enumerate() { | |
print("\(rank.description) = \(rank.toRaw())\n") | |
} | |
/* Output | |
Two = 2 | |
Three = 3 | |
Four = 4 | |
Five = 5 | |
Six = 6 | |
Seven = 7 | |
Eight = 8 | |
Nine = 9 | |
Ten = 10 | |
Jack = 11 | |
Queen = 12 | |
King = 13 | |
Ace = 14 | |
*/ | |
// Enumerate the face cards | |
let faceCardRange = Rank.Jack.toRaw()...Rank.King.toRaw() | |
let faceCards: SequenceOf<Rank> = enumerate(range: faceCardRange) | |
for faceCard in faceCards { | |
print("Face card: \(faceCard.description) = \(faceCard.toRaw())\n") | |
} | |
/* Output | |
Face card: Jack = 11 | |
Face card: Queen = 12 | |
Face card: King = 13 | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@Isuru-Nanayakkara https://gist.github.com/RickPasveer/ab4d3d538082796d68af8b47a14f388d