blob: ad84251320884938d45c44da7ae3d8a7301705d6 [file] [log] [blame]
////===--- _EitherSequence.swift - A sequence type-erasing two sequences -----===//
////
//// This source file is part of the Swift.org open source project
////
//// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
//// Licensed under Apache License v2.0 with Runtime Library Exception
////
//// See https://swift.org/LICENSE.txt for license information
//// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
////
////===----------------------------------------------------------------------===//
// Not public stdlib API, currently used in Mirror.children implementation.
internal enum _Either<Left, Right> {
case left(Left), right(Right)
}
extension _Either {
internal init(_ left: Left, or other: Right.Type) { self = .left(left) }
internal init(_ left: Left) { self = .left(left) }
internal init(_ right: Right) { self = .right(right) }
}
extension _Either: Equatable where Left: Equatable, Right: Equatable {
internal static func == (lhs: Self, rhs: Self) -> Bool {
switch (lhs, rhs) {
case let (.left(l), .left(r)): return l == r
case let (.right(l), .right(r)): return l == r
case (.left, .right), (.right, .left): return false
}
}
}
extension _Either: Comparable where Left: Comparable, Right: Comparable {
internal static func < (lhs: Self, rhs: Self) -> Bool {
switch (lhs, rhs) {
case let (.left(l), .left(r)): return l < r
case let (.right(l), .right(r)): return l < r
case (.left, .right): return true
case (.right, .left): return false
}
}
}
/// A sequence that type erases two sequences. A lighter-weight alternative to
/// AnySequence when more can be statically known, and which is more easily
/// specialized.
///
/// If you only know about one of the types, the second one can be
/// AnySequence, giving you a fast path for the known one.
///
/// If you have 3+ types to erase, you can nest them.
typealias _EitherSequence<L: Sequence, R: Sequence> =
_Either<L,R> where L.Element == R.Element
extension _EitherSequence {
internal struct Iterator {
var left: Left.Iterator?
var right: Right.Iterator?
}
}
extension _Either.Iterator: IteratorProtocol {
internal typealias Element = Left.Element
internal mutating func next() -> Element? {
left?.next() ?? right?.next()
}
}
extension _EitherSequence: Sequence {
internal typealias Element = Left.Element
internal func makeIterator() -> Iterator {
switch self {
case let .left(l):
return Iterator(left: l.makeIterator(), right: nil)
case let .right(r):
return Iterator(left: nil, right: r.makeIterator())
}
}
}
internal typealias _EitherCollection<
T: Collection, U: Collection
> = _EitherSequence<T,U> where T.Element == U.Element
extension _EitherCollection: Collection {
internal typealias Index = _Either<Left.Index, Right.Index>
internal var startIndex: Index {
switch self {
case let .left(s): return .left(s.startIndex)
case let .right(s): return .right(s.startIndex)
}
}
internal var endIndex: Index {
switch self {
case let .left(s): return .left(s.endIndex)
case let .right(s): return .right(s.endIndex)
}
}
internal subscript(position: Index) -> Element {
switch (self,position) {
case let (.left(s),.left(i)): return s[i]
case let (.right(s),.right(i)): return s[i]
default: fatalError("_EitherCollecton: Sequence used with other index type")
}
}
internal func index(after i: Index) -> Index {
switch (self,i) {
case let (.left(s),.left(i)): return .left(s.index(after: i))
case let (.right(s),.right(i)): return .right(s.index(after: i))
default: fatalError("_EitherCollecton: wrong type of index used")
}
}
internal func index(
_ i: Index,
offsetBy distance: Int,
limitedBy limit: Index
) -> Index? {
switch (self,i,limit) {
case let (.left(s),.left(i),.left(limit)):
return s.index(i, offsetBy: distance, limitedBy: limit).map { .left($0) }
case let (.right(s),.right(i),.right(limit)):
return s.index(i, offsetBy: distance, limitedBy: limit).map { .right($0) }
default: fatalError("_EitherCollecton: wrong type of index used")
}
}
internal func index(_ i: Index, offsetBy distance: Int) -> Index {
switch (self,i) {
case let (.left(s),.left(i)): return .left(s.index(i, offsetBy: distance))
case let (.right(s),.right(i)): return .right(s.index(i, offsetBy: distance))
default: fatalError("_EitherCollecton: wrong type of index used")
}
}
internal func distance(from start: Index, to end: Index) -> Int {
switch (self,start,end) {
case let (.left(s),.left(i),.left(j)):
return s.distance(from: i, to: j)
case let (.right(s),.right(i),.right(j)):
return s.distance(from: i, to: j)
default: fatalError("_EitherCollecton: wrong type of index used")
}
}
}
internal typealias _EitherBidirectionalCollection<
L: BidirectionalCollection, R: BidirectionalCollection
> = _Either<L,R> where L.Element == R.Element
extension _EitherBidirectionalCollection: BidirectionalCollection {
internal func index(before i: Index) -> Index {
switch (self,i) {
case let (.left(s),.left(i)): return .left(s.index(before: i))
case let (.right(s),.right(i)): return .right(s.index(before: i))
default: fatalError("_EitherCollecton: wrong type of index used")
}
}
}
internal typealias _EitherRandomAccessCollection<
L: RandomAccessCollection, R: RandomAccessCollection
> = _Either<L,R> where L.Element == R.Element
extension _EitherRandomAccessCollection: RandomAccessCollection { }
extension _Either {
init<C: Collection>(
_ collection: C
) where Right == AnyCollection<C.Element> {
self = .right(AnyCollection(collection))
}
}
extension AnyCollection {
init<L: Collection,R: Collection>(
_ other: _Either<L,R>
) where L.Element == Element, R.Element == Element {
// Strip away the Either and put the actual collection into the existential,
// trying to use the custom initializer from another AnyCollection.
switch other {
case let .left(l as Self): self = .init(l)
case let .right(r as Self): self = .init(r)
case let .left(l): self = .init(l)
case let .right(r): self = .init(r)
}
}
}