Last active
January 3, 2018 23:10
-
-
Save karwa/a1f34ac2ed7b012e8beec8a99c12ab7d to your computer and use it in GitHub Desktop.
Another idea for more convient slicing in Collections.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Another idea for more convient slicing in Collections. | |
/// Lazily-resolved indexes, by their nature, are not really safe to use with a potentially-mutating collection because | |
/// their cached 'base' index might have been invalidated. If you want to use them in that situation, you have to ensure | |
/// they point to locations which will survive the mutation, then manually resolve them *before* mutating. | |
/// | |
/// Or... you use the `Collection.easySlice()` method to do your slicing on a (hopefully) immutable copy | |
/// of the collection. | |
/// | |
final class LazilyResolvedIndex<C: Collection> { | |
var base: C.Index | |
var offset: C.IndexDistance | |
init(base: C.Index, offset: C.IndexDistance) { | |
self.base = base; self.offset = offset | |
} | |
func resolve(in collection: C) -> C.Index { | |
if offset != 0 { | |
base = collection.index(base, offsetBy: offset) | |
offset = 0 | |
} | |
return base | |
} | |
} | |
func += <C>(lhs: LazilyResolvedIndex<C>, rhs: C.IndexDistance) { | |
lhs.offset += rhs | |
} | |
func -= <C>(lhs: LazilyResolvedIndex<C>, rhs: C.IndexDistance) { | |
lhs.offset -= rhs | |
} | |
func + <C>(lhs: LazilyResolvedIndex<C>, rhs: C.IndexDistance) -> LazilyResolvedIndex<C> { | |
return LazilyResolvedIndex(base: lhs.base, offset: lhs.offset + rhs) | |
} | |
func - <C>(lhs: LazilyResolvedIndex<C>, rhs: C.IndexDistance) -> LazilyResolvedIndex<C> { | |
return LazilyResolvedIndex(base: lhs.base, offset: lhs.offset - rhs) | |
} | |
extension Collection { | |
subscript(idx: LazilyResolvedIndex<Self>) -> Element { | |
return self[idx.resolve(in: self)] | |
} | |
subscript(from: Index, to: Index) -> SubSequence { | |
if from < to { return self[from..<to] } | |
else { return self[to..<from] } | |
} | |
subscript(from: LazilyResolvedIndex<Self>, to: LazilyResolvedIndex<Self>) -> SubSequence { | |
return self[from.resolve(in: self), to.resolve(in: self)] | |
} | |
subscript(from: KeyPath<Self, Index>, to: LazilyResolvedIndex<Self>) -> SubSequence { | |
return self[self[keyPath: from], to.resolve(in: self)] | |
} | |
subscript(from: LazilyResolvedIndex<Self>, to: KeyPath<Self, Index>) -> SubSequence { | |
return self[from.resolve(in: self), self[keyPath: to]] | |
} | |
func easySlice(using: (LazilyResolvedIndex<Self>, Self) throws -> Void) rethrows { | |
let idx = LazilyResolvedIndex<Self>(base: startIndex, offset: 0) | |
try using(idx, self) | |
} | |
} | |
let string = "hello everybody!" | |
string.easySlice { idx, string in | |
string[idx] | |
idx += 3 | |
string[idx] | |
idx += 3 | |
string[idx, idx + 5] | |
string[idx, \.endIndex] | |
idx -= 3 | |
string[\.startIndex, idx + 4] | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment