Skip to content

Instantly share code, notes, and snippets.

@kristopherjohnson
Last active May 12, 2017 01:56
Show Gist options
  • Star 25 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save kristopherjohnson/f1cc8baaf0ed0efd326a to your computer and use it in GitHub Desktop.
Save kristopherjohnson/f1cc8baaf0ed0efd326a to your computer and use it in GitHub Desktop.
Helper functions for enumerating values of a Swift enum
// 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
*/
@Isuru-Nanayakkara
Copy link

Can you please update this to Swift 2.2?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment