Skip to content

Instantly share code, notes, and snippets.

@natecook1000
Created June 22, 2021 16:39
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 natecook1000/73e41a9e0906d43439c10e49adc55fe3 to your computer and use it in GitHub Desktop.
Save natecook1000/73e41a9e0906d43439c10e49adc55fe3 to your computer and use it in GitHub Desktop.
// Based on https://gist.github.com/dabrahams/852dfdb0b628e68567b4d97499f196f9
struct Dispatch<Model> {
func apply<A, R>(_ a: A, _ f: (Model) -> R) -> R {
f(a as! Model)
}
}
protocol RandomAccessCollectionDispatch {
func fastCount<C: Collection>(_ x: C) -> Int?
}
extension Dispatch: RandomAccessCollectionDispatch
where Model: RandomAccessCollection
{
func fastCount<C: Collection>(_ x: C) -> Int? {
apply(x) { $0.count }
}
}
extension Collection {
internal var randomAccessDispatch: RandomAccessCollectionDispatch? {
Dispatch<Self>() as? RandomAccessCollectionDispatch
}
}
struct ConditionalCollection<Base: Collection>: Collection {
typealias Index = Base.Index
var base: Base
var startIndex: Index { base.startIndex }
var endIndex: Index { base.endIndex }
func index(after i: Index) -> Index {
base.index(after: i)
}
subscript(position: Index) -> Base.Element {
base[position]
}
}
extension ConditionalCollection: BidirectionalCollection
where Base: BidirectionalCollection
{
func index(before i: Base.Index) -> Base.Index {
base.index(before: i)
}
}
extension ConditionalCollection: RandomAccessCollection
where Base: RandomAccessCollection
{
func distance(from start: Base.Index, to end: Base.Index) -> Int {
base.distance(from: start, to: end)
}
func index(_ i: Base.Index, offsetBy distance: Int) -> Base.Index {
base.index(i, offsetBy: distance)
}
}
func conformanceTest<C: Collection>(_ c: C) {
print(c.randomAccessDispatch?.fastCount(c) as Any)
}
conformanceTest(1...10) // 10
conformanceTest("asdf") // nil
conformanceTest(ConditionalCollection(base: 1...10)) // 10
conformanceTest(ConditionalCollection(base: "asdf")) // nil
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment