@@ -58,42 +58,34 @@ extension FlattenCollection: Collection {
58
58
Index ( outer: base. endIndex, inner: nil )
59
59
}
60
60
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.
61
64
@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) ... ]
68
71
. 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)
73
74
} else {
74
- return Index ( outer: index . outer, inner: nextInner )
75
+ return Index ( outer: outer, inner: inner )
75
76
}
76
77
}
77
78
78
79
@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)
87
84
}
88
85
89
86
@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!]
97
89
}
98
90
99
91
@inlinable
@@ -111,6 +103,153 @@ extension FlattenCollection: Collection {
111
103
112
104
return firstPart + middlePart + lastPart
113
105
}
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
+ }
114
253
}
115
254
116
255
extension FlattenCollection : BidirectionalCollection
@@ -134,6 +273,10 @@ extension FlattenCollection: BidirectionalCollection
134
273
}
135
274
}
136
275
276
+ //===----------------------------------------------------------------------===//
277
+ // joined()
278
+ //===----------------------------------------------------------------------===//
279
+
137
280
extension Collection where Element: Collection {
138
281
@inlinable
139
282
internal func joined( ) -> FlattenCollection < Self > {
0 commit comments