Skip to content

Instantly share code, notes, and snippets.

@khanlou
Last active April 30, 2018 17:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save khanlou/3cfbe22c09db32dc195f548ac90671a7 to your computer and use it in GitHub Desktop.
Save khanlou/3cfbe22c09db32dc195f548ac90671a7 to your computer and use it in GitHub Desktop.
enum InfiniteCollectionIndex<WrappedIndex: Comparable> {
case reachable(WrappedIndex)
case unreachable
}
extension InfiniteCollectionIndex: Comparable {
static func == (lhs: InfiniteCollectionIndex, rhs: InfiniteCollectionIndex) -> Bool {
switch (lhs, rhs) {
case (.unreachable, .unreachable):
return true
case let (.reachable(left), .reachable(right)):
return left == right
case (.reachable, .unreachable):
return false
case (.unreachable, .reachable):
return false
}
}
static func < (lhs: InfiniteCollectionIndex, rhs: InfiniteCollectionIndex) -> Bool {
switch (lhs, rhs) {
case (.unreachable, .unreachable):
return false
case let (.reachable(left), .reachable(right)):
return left < right
case (.reachable, .unreachable):
return true
case (.unreachable, .reachable):
return false
}
}
}
extension InfiniteCollectionIndex {
func assumingReachable<T>(_ block: (WrappedIndex) -> T) -> T {
switch self {
case .unreachable:
fatalError("You can't operate on an unreachable index")
case let .reachable(wrapped):
return block(wrapped)
}
}
func makeNextReachableIndex(_ block: (WrappedIndex) -> WrappedIndex) -> InfiniteCollectionIndex {
return .reachable(assumingReachable(block))
}
}
struct FibIndex {
let first: Int
let second: Int
}
extension FibIndex: Comparable {
static func == (lhs: FibIndex, rhs: FibIndex) -> Bool {
return lhs.first == rhs.first && lhs.second == rhs.second
}
static func < (lhs: FibIndex, rhs: FibIndex) -> Bool {
return lhs.first < rhs.first
}
}
struct FibonacciCollection: Collection {
typealias Index = InfiniteCollectionIndex<FibIndex>
var startIndex: Index {
return .reachable(FibIndex(first: 0, second: 1))
}
func index(after previous: Index) -> Index {
return previous.makeNextReachableIndex({ FibIndex(first: $0.second, second: $0.first + $0.second) })
}
var endIndex: Index {
return .unreachable
}
subscript(index: Index) -> Int {
return index.assumingReachable({ $0.first + $0.second })
}
}
let fib = FibonacciCollection()
Array(fib.prefix(10))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment