Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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

This comment has been minimized.

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

This comment has been minimized.

Copy link
Owner 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
You can’t perform that action at this time.