Skip to content

Instantly share code, notes, and snippets.

@karwa
Last active January 3, 2018 22:32
Show Gist options
  • Save karwa/04cc43431951f24ae9334ba8a25e6a31 to your computer and use it in GitHub Desktop.
Save karwa/04cc43431951f24ae9334ba8a25e6a31 to your computer and use it in GitHub Desktop.
index expressions for collections
enum IndexType<C: Collection> {
case keypath(KeyPath<C, C.Index>)
case index(C.Index)
}
struct IndexExpression<C: Collection> {
let base: IndexType<C>
let distance: C.IndexDistance
func resolve(in collection: C) -> C.Index {
let baseIdx: C.Index
switch base {
case .index(let idx): baseIdx = idx
case .keypath(let kp): baseIdx = collection[keyPath: kp]
}
return collection.index(baseIdx, offsetBy: distance)
}
}
func + <C>(lhs: IndexExpression<C>, distance: C.IndexDistance) -> IndexExpression<C> {
return IndexExpression(base: lhs.base, distance: lhs.distance + distance)
}
func - <C>(lhs: IndexExpression<C>, distance: C.IndexDistance) -> IndexExpression<C> {
return IndexExpression(base: lhs.base, distance: lhs.distance - distance)
}
func + <C: Collection>(kp: KeyPath<C, C.Index>, distance: C.IndexDistance) -> IndexExpression<C> {
return IndexExpression(base: .keypath(kp), distance: distance)
}
func - <C: Collection>(kp: KeyPath<C, C.Index>, distance: C.IndexDistance) -> IndexExpression<C> {
return IndexExpression(base: .keypath(kp), distance: -1 * distance)
}
func + <C: Collection>(idx: C.Index, distance: C.IndexDistance) -> IndexExpression<C> {
return IndexExpression(base: .index(idx), distance: distance)
}
func - <C: Collection>(idx: C.Index, distance: C.IndexDistance) -> IndexExpression<C> {
return IndexExpression(base: .index(idx), distance: -1 * distance)
}
extension Collection {
subscript(expr: IndexExpression<Self>) -> Element {
return self[expr.resolve(in: self)]
}
}
let string = "hello everybody!"
let myIdx = string.startIndex
string[myIdx + 2]
string[string.startIndex + 7]
string[\.endIndex - 3]
@ole
Copy link

ole commented Jan 3, 2018

Moving the IndexType enum outside the IndexExpression struct works (Xcode 9.2, Swift 4.0.3):

enum IndexType<C: Collection> {
    case keypath(KeyPath<C, C.Index>)
    case index(C.Index)
}

struct IndexExpression<C: Collection> {
    let base: IndexType<C>
    let distance: C.IndexDistance

    func resolve(in collection: C) -> C.Index {
        let baseIdx: C.Index
        switch base {
        case .index(let idx):  baseIdx = idx
        case .keypath(let kp): baseIdx = collection[keyPath: kp]
        }
        return collection.index(baseIdx, offsetBy: distance)
    }
}

@karwa
Copy link
Author

karwa commented Jan 3, 2018

Oh great, thanks for the tip!

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