Skip to content

Commit c67023d

Browse files
author
Tim Vermeulen
committed
Add joined(by:)
1 parent e25cf27 commit c67023d

File tree

5 files changed

+1009
-0
lines changed

5 files changed

+1009
-0
lines changed
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift Algorithms open source project
4+
//
5+
// Copyright (c) 2021 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
//
10+
//===----------------------------------------------------------------------===//
11+
12+
//===----------------------------------------------------------------------===//
13+
// Either
14+
//===----------------------------------------------------------------------===//
15+
16+
@usableFromInline
17+
internal enum Either<Left, Right> {
18+
case left(Left)
19+
case right(Right)
20+
}
21+
22+
extension Either: Equatable where Left: Equatable, Right: Equatable {
23+
@usableFromInline
24+
internal static func == (lhs: Self, rhs: Self) -> Bool {
25+
switch (lhs, rhs) {
26+
case let (.left(lhs), .left(rhs)):
27+
return lhs == rhs
28+
case let (.right(lhs), .right(rhs)):
29+
return lhs == rhs
30+
case (.left, .right), (.right, .left):
31+
return false
32+
}
33+
}
34+
}
35+
36+
extension Either: Comparable where Left: Comparable, Right: Comparable {
37+
@usableFromInline
38+
internal static func < (lhs: Self, rhs: Self) -> Bool {
39+
switch (lhs, rhs) {
40+
case let (.left(lhs), .left(rhs)):
41+
return lhs < rhs
42+
case let (.right(lhs), .right(rhs)):
43+
return lhs < rhs
44+
case (.left, .right):
45+
return true
46+
case (.right, .left):
47+
return false
48+
}
49+
}
50+
}
51+
52+
//===----------------------------------------------------------------------===//
53+
// EitherSequence
54+
//===----------------------------------------------------------------------===//
55+
56+
@usableFromInline
57+
internal enum EitherSequence<Left: Sequence, Right: Sequence>
58+
where Left.Element == Right.Element
59+
{
60+
case left(Left)
61+
case right(Right)
62+
}
63+
64+
extension EitherSequence: Sequence {
65+
public struct Iterator: IteratorProtocol {
66+
var left: Left.Iterator?
67+
var right: Right.Iterator?
68+
69+
public mutating func next() -> Left.Element? {
70+
left?.next() ?? right?.next()
71+
}
72+
}
73+
74+
@usableFromInline
75+
func makeIterator() -> Iterator {
76+
switch self {
77+
case .left(let left):
78+
return Iterator(left: left.makeIterator(), right: nil)
79+
case .right(let right):
80+
return Iterator(left: nil, right: right.makeIterator())
81+
}
82+
}
83+
}
84+
85+
extension EitherSequence: Collection
86+
where Left: Collection, Right: Collection, Left.Element == Right.Element
87+
{
88+
@usableFromInline
89+
internal typealias Index = Either<Left.Index, Right.Index>
90+
91+
@inlinable
92+
internal var startIndex: Index {
93+
switch self {
94+
case .left(let s):
95+
return .left(s.startIndex)
96+
case .right(let s):
97+
return .right(s.startIndex)
98+
}
99+
}
100+
101+
@inlinable
102+
internal var endIndex: Index {
103+
switch self {
104+
case .left(let s):
105+
return .left(s.endIndex)
106+
case .right(let s):
107+
return .right(s.endIndex)
108+
}
109+
}
110+
111+
@inlinable
112+
internal subscript(position: Index) -> Element {
113+
switch (self, position) {
114+
case let (.left(s), .left(i)):
115+
return s[i]
116+
case let (.right(s), .right(i)):
117+
return s[i]
118+
default:
119+
fatalError()
120+
}
121+
}
122+
123+
@inlinable
124+
internal func index(after i: Index) -> Index {
125+
switch (self,i) {
126+
case let (.left(s), .left(i)):
127+
return .left(s.index(after: i))
128+
case let (.right(s), .right(i)):
129+
return .right(s.index(after: i))
130+
default:
131+
fatalError()
132+
}
133+
}
134+
135+
@inlinable
136+
internal func index(
137+
_ i: Index,
138+
offsetBy distance: Int,
139+
limitedBy limit: Index
140+
) -> Index? {
141+
switch (self, i, limit) {
142+
case let (.left(s), .left(i), .left(limit)):
143+
return s.index(i, offsetBy: distance, limitedBy: limit).map { .left($0) }
144+
case let (.right(s), .right(i), .right(limit)):
145+
return s.index(i, offsetBy: distance, limitedBy: limit).map { .right($0) }
146+
default:
147+
fatalError()
148+
}
149+
}
150+
151+
@inlinable
152+
internal func index(_ i: Index, offsetBy distance: Int) -> Index {
153+
switch (self, i) {
154+
case let (.left(s), .left(i)):
155+
return .left(s.index(i, offsetBy: distance))
156+
case let (.right(s), .right(i)):
157+
return .right(s.index(i, offsetBy: distance))
158+
default:
159+
fatalError()
160+
}
161+
}
162+
163+
@inlinable
164+
internal func distance(from start: Index, to end: Index) -> Int {
165+
switch (self, start, end) {
166+
case let (.left(s), .left(i), .left(j)):
167+
return s.distance(from: i, to: j)
168+
case let (.right(s), .right(i), .right(j)):
169+
return s.distance(from: i, to: j)
170+
default:
171+
fatalError()
172+
}
173+
}
174+
}
175+
176+
extension EitherSequence: BidirectionalCollection
177+
where Left: BidirectionalCollection, Right: BidirectionalCollection
178+
{
179+
@inlinable
180+
internal func index(before i: Index) -> Index {
181+
switch (self, i) {
182+
case let (.left(s), .left(i)):
183+
return .left(s.index(before: i))
184+
case let (.right(s), .right(i)):
185+
return .right(s.index(before: i))
186+
default:
187+
fatalError()
188+
}
189+
}
190+
}
191+
192+
extension EitherSequence: RandomAccessCollection
193+
where Left: RandomAccessCollection, Right: RandomAccessCollection {}
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift Algorithms open source project
4+
//
5+
// Copyright (c) 2021 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
//
10+
//===----------------------------------------------------------------------===//
11+
12+
@usableFromInline
13+
internal struct FlattenCollection<Base: Collection> where Base.Element: Collection {
14+
@usableFromInline
15+
internal let base: Base
16+
17+
@usableFromInline
18+
internal let indexOfFirstNonEmptyElement: Base.Index
19+
20+
@inlinable
21+
internal init(base: Base) {
22+
self.base = base
23+
self.indexOfFirstNonEmptyElement = base.endOfPrefix(while: { $0.isEmpty })
24+
}
25+
}
26+
27+
extension FlattenCollection: Collection {
28+
@usableFromInline
29+
internal struct Index: Comparable {
30+
@usableFromInline
31+
internal let outer: Base.Index
32+
33+
@usableFromInline
34+
internal let inner: Base.Element.Index?
35+
36+
@inlinable
37+
init(outer: Base.Index, inner: Base.Element.Index?) {
38+
self.outer = outer
39+
self.inner = inner
40+
}
41+
42+
@inlinable
43+
internal static func < (lhs: Self, rhs: Self) -> Bool {
44+
guard lhs.outer == rhs.outer else { return lhs.outer < rhs.outer }
45+
return lhs.inner == nil ? false : lhs.inner! < rhs.inner!
46+
}
47+
}
48+
49+
@inlinable
50+
internal var startIndex: Index {
51+
let outer = indexOfFirstNonEmptyElement
52+
let inner = outer == base.endIndex ? nil : base[outer].startIndex
53+
return Index(outer: outer, inner: inner)
54+
}
55+
56+
@inlinable
57+
internal var endIndex: Index {
58+
Index(outer: base.endIndex, inner: nil)
59+
}
60+
61+
@inlinable
62+
internal func index(after index: Index) -> Index {
63+
let element = base[index.outer]
64+
let nextInner = element.index(after: index.inner!)
65+
66+
if nextInner == element.endIndex {
67+
let nextOuter = base[base.index(after: index.outer)...]
68+
.endOfPrefix(while: { $0.isEmpty })
69+
let nextInner = nextOuter == base.endIndex
70+
? nil
71+
: base[nextOuter].startIndex
72+
return Index(outer: nextOuter, inner: nextInner)
73+
} else {
74+
return Index(outer: index.outer, inner: nextInner)
75+
}
76+
}
77+
78+
@inlinable
79+
internal subscript(position: Index) -> Base.Element.Element {
80+
base[position.outer][position.inner!]
81+
}
82+
83+
@inlinable
84+
internal func index(_ index: Index, offsetBy distance: Int) -> Index {
85+
// TODO
86+
fatalError()
87+
}
88+
89+
@inlinable
90+
internal func index(
91+
_ index: Index,
92+
offsetBy distance: Int,
93+
limitedBy limit: Index
94+
) -> Index? {
95+
// TODO
96+
fatalError()
97+
}
98+
99+
@inlinable
100+
internal func distance(from start: Index, to end: Index) -> Int {
101+
guard start.outer <= end.outer
102+
else { return -distance(from: end, to: start) }
103+
guard let startInner = start.inner
104+
else { return 0 }
105+
guard start.outer != end.outer
106+
else { return base[start.outer].distance(from: startInner, to: end.inner!) }
107+
108+
let firstPart = base[start.outer][startInner...].count
109+
let middlePart = base[start.outer..<end.outer].dropFirst().reduce(0, { $0 + $1.count })
110+
let lastPart = end.inner.map { base[end.outer][..<$0].count } ?? 0
111+
112+
return firstPart + middlePart + lastPart
113+
}
114+
}
115+
116+
extension FlattenCollection: BidirectionalCollection
117+
where Base: BidirectionalCollection, Base.Element: BidirectionalCollection
118+
{
119+
@inlinable
120+
internal func index(before index: Index) -> Index {
121+
if let inner = index.inner {
122+
let element = base[index.outer]
123+
124+
if inner != element.startIndex {
125+
let previousInner = element.index(before: inner)
126+
return Index(outer: index.outer, inner: previousInner)
127+
}
128+
}
129+
130+
let previousOuter = base[..<index.outer].lastIndex(where: { !$0.isEmpty })!
131+
let element = base[previousOuter]
132+
let previousInner = element.index(before: element.endIndex)
133+
return Index(outer: previousOuter, inner: previousInner)
134+
}
135+
}
136+
137+
extension Collection where Element: Collection {
138+
@inlinable
139+
internal func joined() -> FlattenCollection<Self> {
140+
FlattenCollection(base: self)
141+
}
142+
}

0 commit comments

Comments
 (0)