Skip to content

Instantly share code, notes, and snippets.

@karwa
Last active January 3, 2018 23:10
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 karwa/a1f34ac2ed7b012e8beec8a99c12ab7d to your computer and use it in GitHub Desktop.
Save karwa/a1f34ac2ed7b012e8beec8a99c12ab7d to your computer and use it in GitHub Desktop.
Another idea for more convient slicing in Collections.
// 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