Skip to content

Commit ad834c4

Browse files
author
Tim Vermeulen
committed
Add missing implementations
1 parent 1cbda6e commit ad834c4

File tree

5 files changed

+423
-76
lines changed

5 files changed

+423
-76
lines changed

Sources/Algorithms/FlattenCollection.swift

Lines changed: 169 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -58,42 +58,34 @@ extension FlattenCollection: Collection {
5858
Index(outer: base.endIndex, inner: nil)
5959
}
6060

61+
/// Forms an index from a pair of base indices, normalizing
62+
/// `(i, base2.endIndex)` to `(base1.index(after: i), base2.startIndex)` if
63+
/// necessary.
6164
@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)...]
65+
internal func normalizeIndex(
66+
outer: Base.Index,
67+
inner: Base.Element.Index
68+
) -> Index {
69+
if inner == base[outer].endIndex {
70+
let outer = base[base.index(after: outer)...]
6871
.endOfPrefix(while: { $0.isEmpty })
69-
let nextInner = nextOuter == base.endIndex
70-
? nil
71-
: base[nextOuter].startIndex
72-
return Index(outer: nextOuter, inner: nextInner)
72+
let inner = outer == base.endIndex ? nil : base[outer].startIndex
73+
return Index(outer: outer, inner: inner)
7374
} else {
74-
return Index(outer: index.outer, inner: nextInner)
75+
return Index(outer: outer, inner: inner)
7576
}
7677
}
7778

7879
@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()
80+
internal func index(after index: Index) -> Index {
81+
let element = base[index.outer]
82+
let nextInner = element.index(after: index.inner!)
83+
return normalizeIndex(outer: index.outer, inner: nextInner)
8784
}
8885

8986
@inlinable
90-
internal func index(
91-
_ index: Index,
92-
offsetBy distance: Int,
93-
limitedBy limit: Index
94-
) -> Index? {
95-
// TODO
96-
fatalError()
87+
internal subscript(position: Index) -> Base.Element.Element {
88+
base[position.outer][position.inner!]
9789
}
9890

9991
@inlinable
@@ -111,6 +103,153 @@ extension FlattenCollection: Collection {
111103

112104
return firstPart + middlePart + lastPart
113105
}
106+
107+
@inlinable
108+
internal func index(_ index: Index, offsetBy distance: Int) -> Index {
109+
guard distance != 0 else { return index }
110+
111+
return distance > 0
112+
? offsetForward(index, by: distance)
113+
: offsetBackward(index, by: -distance)
114+
}
115+
116+
@inlinable
117+
internal func index(
118+
_ index: Index,
119+
offsetBy distance: Int,
120+
limitedBy limit: Index
121+
) -> Index? {
122+
guard distance != 0 else { return index }
123+
124+
if distance > 0 {
125+
return limit >= index
126+
? offsetForward(index, by: distance, limitedBy: limit)
127+
: offsetForward(index, by: distance)
128+
} else {
129+
return limit <= index
130+
? offsetBackward(index, by: -distance, limitedBy: limit)
131+
: offsetBackward(index, by: -distance)
132+
}
133+
}
134+
135+
@inlinable
136+
internal func offsetForward(_ i: Index, by distance: Int) -> Index {
137+
guard let index = offsetForward(i, by: distance, limitedBy: endIndex)
138+
else { fatalError("Index is out of bounds") }
139+
return index
140+
}
141+
142+
@inlinable
143+
internal func offsetBackward(_ i: Index, by distance: Int) -> Index {
144+
guard let index = offsetBackward(i, by: distance, limitedBy: startIndex)
145+
else { fatalError("Index is out of bounds") }
146+
return index
147+
}
148+
149+
@inlinable
150+
internal func offsetForward(
151+
_ index: Index, by distance: Int, limitedBy limit: Index
152+
) -> Index? {
153+
assert(distance > 0)
154+
assert(limit >= index)
155+
156+
if index.outer == limit.outer {
157+
if let indexInner = index.inner, let limitInner = limit.inner {
158+
return base[index.outer]
159+
.index(indexInner, offsetBy: distance, limitedBy: limitInner)
160+
.map { inner in Index(outer: index.outer, inner: inner) }
161+
} else {
162+
// `index` and `limit` are both `endIndex`
163+
return nil
164+
}
165+
}
166+
167+
// `index <= limit` and `index.outer != limit.outer`, so `index != endIndex`
168+
let indexInner = index.inner!
169+
let element = base[index.outer]
170+
171+
if let inner = element.index(
172+
indexInner,
173+
offsetBy: distance,
174+
limitedBy: element.endIndex
175+
) {
176+
return normalizeIndex(outer: index.outer, inner: inner)
177+
}
178+
179+
var remainder = distance - element[indexInner...].count
180+
var outer = base.index(after: index.outer)
181+
182+
while outer != limit.outer {
183+
let element = base[outer]
184+
185+
if let inner = element.index(
186+
element.startIndex,
187+
offsetBy: remainder,
188+
limitedBy: element.endIndex
189+
) {
190+
return normalizeIndex(outer: outer, inner: inner)
191+
}
192+
193+
remainder -= element.count
194+
base.formIndex(after: &outer)
195+
}
196+
197+
if let limitInner = limit.inner {
198+
let element = base[outer]
199+
return element.index(element.startIndex, offsetBy: remainder, limitedBy: limitInner)
200+
.map { inner in Index(outer: outer, inner: inner) }
201+
} else {
202+
return nil
203+
}
204+
}
205+
206+
@inlinable
207+
internal func offsetBackward(
208+
_ index: Index, by distance: Int, limitedBy limit: Index
209+
) -> Index? {
210+
assert(distance > 0)
211+
assert(limit <= index)
212+
213+
if index.outer == limit.outer {
214+
if let indexInner = index.inner, let limitInner = limit.inner {
215+
return base[index.outer]
216+
.index(indexInner, offsetBy: -distance, limitedBy: limitInner)
217+
.map { inner in Index(outer: index.outer, inner: inner) }
218+
} else {
219+
// `index` and `limit` are both `endIndex`
220+
return nil
221+
}
222+
}
223+
224+
var remainder = distance
225+
226+
if let indexInner = index.inner {
227+
let element = base[index.outer]
228+
229+
if let inner = element.index(indexInner, offsetBy: -remainder, limitedBy: element.startIndex) {
230+
return Index(outer: index.outer, inner: inner)
231+
}
232+
233+
remainder -= element[..<indexInner].count
234+
}
235+
236+
var outer = base.index(index.outer, offsetBy: -1)
237+
238+
while outer != limit.outer {
239+
let element = base[outer]
240+
241+
if let inner = element.index(element.endIndex, offsetBy: -remainder, limitedBy: element.startIndex) {
242+
return Index(outer: outer, inner: inner)
243+
}
244+
245+
remainder -= element.count
246+
base.formIndex(&outer, offsetBy: -1)
247+
}
248+
249+
let element = base[outer]
250+
return element.index(element.endIndex, offsetBy: -remainder, limitedBy: limit.inner!)
251+
.map { inner in Index(outer: outer, inner: inner) }
252+
}
114253
}
115254

116255
extension FlattenCollection: BidirectionalCollection
@@ -134,6 +273,10 @@ extension FlattenCollection: BidirectionalCollection
134273
}
135274
}
136275

276+
//===----------------------------------------------------------------------===//
277+
// joined()
278+
//===----------------------------------------------------------------------===//
279+
137280
extension Collection where Element: Collection {
138281
@inlinable
139282
internal func joined() -> FlattenCollection<Self> {

0 commit comments

Comments
 (0)