Skip to content

Instantly share code, notes, and snippets.

@natecook1000
Last active November 12, 2018 12:22
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save natecook1000/77ecc5a60b5b66901185d87c93e0664c to your computer and use it in GitHub Desktop.
Save natecook1000/77ecc5a60b5b66901185d87c93e0664c to your computer and use it in GitHub Desktop.
/// A dictionary wrapper that uses a `CaseIterable` type as its key.
/// This differs from a dictionary in two ways:
///
/// - Key-value pairs are accessed in a fixed order, which is the same
/// as the `Key`'s `allCases` property.
/// - Every possible key must have a value given, so using the key-based
/// subscript returns a non-optional value.
struct CaseMap<Key: CaseIterable & Hashable, Value> : Collection {
typealias Index = Key.AllCases.Index
var data: [Key: Value]
init(_ elements: [Key: Value]) {
assert(elements.count == Key.allCases.count)
for key in Key.allCases {
assert(elements.keys.contains(key))
}
self.data = elements
}
var startIndex: Index {
return Key.allCases.startIndex
}
var endIndex: Index {
return Key.allCases.endIndex
}
func index(after i: Index) -> Index {
assert(i != endIndex)
return Key.allCases.index(after: i)
}
func mapValues<T>(_ transform: (Value) -> T) -> CaseMap<Key, T> {
return CaseMap<Key, T>(data.mapValues(transform))
}
subscript(i: Index) -> (key: Key, value: Value) {
return (Key.allCases[i], data[Key.allCases[i]]!)
}
subscript(key: Key) -> Value {
get { return data[key]! }
set { data[key]! = newValue }
}
}
// Usage:
enum Suit: String, CaseIterable {
case spades
case hearts
case clubs
case diamonds
}
Suit.allCases
// [Suit.spades, Suit.hearts, Suit.clubs, Suit.diamonds]
Suit.allCases.map({ $0.rawValue })
// ["spades", "hearts", "clubs", "diamonds"]
let m = CaseMap<Suit, String>([.spades: "S", .hearts: "H", .clubs: "C", .diamonds: "D"])
// ...
for (suit, char) in m {
print("\(suit): \(char)")
}
// spades: S
// hearts: H
// clubs: C
// diamonds: D
m[.clubs]
// "C" (no optionals here!)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment