@@ -15,13 +15,28 @@ struct SplitCollection<Searcher: CollectionSearcher> {
15
15
public typealias Base = Searcher . Searched
16
16
17
17
let ranges : RangesCollection < Searcher >
18
-
19
- init ( ranges: RangesCollection < Searcher > ) {
18
+ var maxSplits : Int
19
+ var omittingEmptySubsequences : Bool
20
+
21
+ init (
22
+ ranges: RangesCollection < Searcher > ,
23
+ maxSplits: Int ,
24
+ omittingEmptySubsequences: Bool )
25
+ {
20
26
self . ranges = ranges
27
+ self . maxSplits = maxSplits
28
+ self . omittingEmptySubsequences = omittingEmptySubsequences
21
29
}
22
30
23
- init ( base: Base , searcher: Searcher ) {
31
+ init (
32
+ base: Base ,
33
+ searcher: Searcher ,
34
+ maxSplits: Int ,
35
+ omittingEmptySubsequences: Bool )
36
+ {
24
37
self . ranges = base. ranges ( of: searcher)
38
+ self . maxSplits = maxSplits
39
+ self . omittingEmptySubsequences = omittingEmptySubsequences
25
40
}
26
41
}
27
42
@@ -30,97 +45,127 @@ extension SplitCollection: Sequence {
30
45
let base : Base
31
46
var index : Base . Index
32
47
var ranges : RangesCollection < Searcher > . Iterator
33
- var isDone : Bool
34
-
35
- init ( ranges: RangesCollection < Searcher > ) {
48
+ var maxSplits : Int
49
+ var omittingEmptySubsequences : Bool
50
+
51
+ var splitCounter = 0
52
+ var isDone = false
53
+
54
+ init (
55
+ ranges: RangesCollection < Searcher > ,
56
+ maxSplits: Int ,
57
+ omittingEmptySubsequences: Bool
58
+ ) {
36
59
self . base = ranges. base
37
60
self . index = base. startIndex
38
61
self . ranges = ranges. makeIterator ( )
39
- self . isDone = false
62
+ self . maxSplits = maxSplits
63
+ self . omittingEmptySubsequences = omittingEmptySubsequences
40
64
}
41
65
42
66
public mutating func next( ) -> Base . SubSequence ? {
43
67
guard !isDone else { return nil }
44
68
45
- guard let range = ranges. next ( ) else {
69
+ /// Return the rest of base if it's non-empty or we're including
70
+ /// empty subsequences.
71
+ func finish( ) -> Base . SubSequence ? {
46
72
isDone = true
47
- return base [ index... ]
73
+ return index == base. endIndex && omittingEmptySubsequences
74
+ ? nil
75
+ : base [ index... ]
76
+ }
77
+
78
+ if splitCounter >= maxSplits {
79
+ return finish ( )
48
80
}
49
81
50
- defer { index = range. upperBound }
51
- return base [ index..< range. lowerBound]
82
+ while true {
83
+ // If there are no more ranges that matched, return the rest of `base`.
84
+ guard let range = ranges. next ( ) else {
85
+ return finish ( )
86
+ }
87
+
88
+ defer { index = range. upperBound }
89
+
90
+ if omittingEmptySubsequences && index == range. lowerBound {
91
+ continue
92
+ }
93
+
94
+ splitCounter += 1
95
+ return base [ index..< range. lowerBound]
96
+ }
52
97
}
53
98
}
54
99
55
100
public func makeIterator( ) -> Iterator {
56
- Iterator ( ranges: ranges)
57
- }
58
- }
59
-
60
- extension SplitCollection : Collection {
61
- public struct Index {
62
- var start : Base . Index
63
- var base : RangesCollection < Searcher > . Index
64
- var isEndIndex : Bool
65
- }
66
-
67
- public var startIndex : Index {
68
- let base = ranges. startIndex
69
- return Index ( start: ranges. base. startIndex, base: base, isEndIndex: false )
70
- }
71
-
72
- public var endIndex : Index {
73
- Index ( start: ranges. base. endIndex, base: ranges. endIndex, isEndIndex: true )
74
- }
75
-
76
- public func formIndex( after index: inout Index ) {
77
- guard !index. isEndIndex else { fatalError ( " Cannot advance past endIndex " ) }
78
-
79
- if let range = index. base. range {
80
- let newStart = range. upperBound
81
- ranges. formIndex ( after: & index. base)
82
- index. start = newStart
83
- } else {
84
- index. isEndIndex = true
85
- }
86
- }
87
-
88
- public func index( after index: Index ) -> Index {
89
- var index = index
90
- formIndex ( after: & index)
91
- return index
92
- }
93
-
94
- public subscript( index: Index ) -> Base . SubSequence {
95
- guard !index. isEndIndex else {
96
- fatalError ( " Cannot subscript using endIndex " )
97
- }
98
- let end = index. base. range? . lowerBound ?? ranges. base. endIndex
99
- return ranges. base [ index. start..< end]
101
+ Iterator ( ranges: ranges, maxSplits: maxSplits, omittingEmptySubsequences: omittingEmptySubsequences)
100
102
}
101
103
}
102
104
103
- extension SplitCollection . Index : Comparable {
104
- static func == ( lhs: Self , rhs: Self ) -> Bool {
105
- switch ( lhs. isEndIndex, rhs. isEndIndex) {
106
- case ( false , false ) :
107
- return lhs. start == rhs. start
108
- case ( let lhs, let rhs) :
109
- return lhs == rhs
110
- }
111
- }
112
-
113
- static func < ( lhs: Self , rhs: Self ) -> Bool {
114
- switch ( lhs. isEndIndex, rhs. isEndIndex) {
115
- case ( true , _) :
116
- return false
117
- case ( _, true ) :
118
- return true
119
- case ( false , false ) :
120
- return lhs. start < rhs. start
121
- }
122
- }
123
- }
105
+ //extension SplitCollection: Collection {
106
+ // public struct Index {
107
+ // var start: Base.Index
108
+ // var base: RangesCollection<Searcher>.Index
109
+ // var isEndIndex: Bool
110
+ // }
111
+ //
112
+ // public var startIndex: Index {
113
+ // let base = ranges.startIndex
114
+ // return Index(start: ranges.base.startIndex, base: base, isEndIndex: false)
115
+ // }
116
+ //
117
+ // public var endIndex: Index {
118
+ // Index(start: ranges.base.endIndex, base: ranges.endIndex, isEndIndex: true)
119
+ // }
120
+ //
121
+ // public func formIndex(after index: inout Index) {
122
+ // guard !index.isEndIndex else { fatalError("Cannot advance past endIndex") }
123
+ //
124
+ // if let range = index.base.range {
125
+ // let newStart = range.upperBound
126
+ // ranges.formIndex(after: &index.base)
127
+ // index.start = newStart
128
+ // } else {
129
+ // index.isEndIndex = true
130
+ // }
131
+ // }
132
+ //
133
+ // public func index(after index: Index) -> Index {
134
+ // var index = index
135
+ // formIndex(after: &index)
136
+ // return index
137
+ // }
138
+ //
139
+ // public subscript(index: Index) -> Base.SubSequence {
140
+ // guard !index.isEndIndex else {
141
+ // fatalError("Cannot subscript using endIndex")
142
+ // }
143
+ // let end = index.base.range?.lowerBound ?? ranges.base.endIndex
144
+ // return ranges.base[index.start..<end]
145
+ // }
146
+ //}
147
+ //
148
+ //extension SplitCollection.Index: Comparable {
149
+ // static func == (lhs: Self, rhs: Self) -> Bool {
150
+ // switch (lhs.isEndIndex, rhs.isEndIndex) {
151
+ // case (false, false):
152
+ // return lhs.start == rhs.start
153
+ // case (let lhs, let rhs):
154
+ // return lhs == rhs
155
+ // }
156
+ // }
157
+ //
158
+ // static func < (lhs: Self, rhs: Self) -> Bool {
159
+ // switch (lhs.isEndIndex, rhs.isEndIndex) {
160
+ // case (true, _):
161
+ // return false
162
+ // case (_, true):
163
+ // return true
164
+ // case (false, false):
165
+ // return lhs.start < rhs.start
166
+ // }
167
+ // }
168
+ //}
124
169
125
170
// MARK: `ReversedSplitCollection`
126
171
@@ -176,10 +221,15 @@ extension ReversedSplitCollection: Sequence {
176
221
177
222
extension Collection {
178
223
func split< Searcher: CollectionSearcher > (
179
- by separator: Searcher
224
+ by separator: Searcher ,
225
+ maxSplits: Int ,
226
+ omittingEmptySubsequences: Bool
180
227
) -> SplitCollection < Searcher > where Searcher. Searched == Self {
181
- // TODO: `maxSplits`, `omittingEmptySubsequences`?
182
- SplitCollection ( base: self , searcher: separator)
228
+ SplitCollection (
229
+ base: self ,
230
+ searcher: separator,
231
+ maxSplits: maxSplits,
232
+ omittingEmptySubsequences: omittingEmptySubsequences)
183
233
}
184
234
}
185
235
@@ -198,9 +248,11 @@ extension BidirectionalCollection {
198
248
extension Collection {
199
249
// TODO: Non-escaping and throwing
200
250
func split(
201
- whereSeparator predicate: @escaping ( Element ) -> Bool
251
+ whereSeparator predicate: @escaping ( Element ) -> Bool ,
252
+ maxSplits: Int ,
253
+ omittingEmptySubsequences: Bool
202
254
) -> SplitCollection < PredicateConsumer < Self > > {
203
- split ( by: PredicateConsumer ( predicate: predicate) )
255
+ split ( by: PredicateConsumer ( predicate: predicate) , maxSplits : maxSplits , omittingEmptySubsequences : omittingEmptySubsequences )
204
256
}
205
257
}
206
258
@@ -216,9 +268,11 @@ extension BidirectionalCollection where Element: Equatable {
216
268
217
269
extension Collection where Element: Equatable {
218
270
func split(
219
- by separator: Element
271
+ by separator: Element ,
272
+ maxSplits: Int ,
273
+ omittingEmptySubsequences: Bool
220
274
) -> SplitCollection < PredicateConsumer < Self > > {
221
- split ( whereSeparator: { $0 == separator } )
275
+ split ( whereSeparator: { $0 == separator } , maxSplits : maxSplits , omittingEmptySubsequences : omittingEmptySubsequences )
222
276
}
223
277
}
224
278
@@ -234,10 +288,12 @@ extension BidirectionalCollection where Element: Equatable {
234
288
235
289
extension Collection where Element: Equatable {
236
290
@_disfavoredOverload
237
- func split< S: Sequence > (
238
- by separator: S
239
- ) -> SplitCollection < ZSearcher < Self > > where S. Element == Element {
240
- split ( by: ZSearcher ( pattern: Array ( separator) , by: == ) )
291
+ func split< C: Collection > (
292
+ by separator: C ,
293
+ maxSplits: Int ,
294
+ omittingEmptySubsequences: Bool
295
+ ) -> SplitCollection < ZSearcher < Self > > where C. Element == Element {
296
+ split ( by: ZSearcher ( pattern: Array ( separator) , by: == ) , maxSplits: maxSplits, omittingEmptySubsequences: omittingEmptySubsequences)
241
297
}
242
298
243
299
// FIXME: Return `some Collection<SubSequence>` for SE-0346
@@ -247,10 +303,12 @@ extension Collection where Element: Equatable {
247
303
/// - Returns: A collection of subsequences, split from this collection's
248
304
/// elements.
249
305
@available ( SwiftStdlib 5 . 7 , * )
250
- public func split< S: Sequence > (
251
- by separator: S
252
- ) -> [ SubSequence ] where S. Element == Element {
253
- Array ( split ( by: ZSearcher ( pattern: Array ( separator) , by: == ) ) )
306
+ public func split< C: Collection > (
307
+ separator: C ,
308
+ maxSplits: Int = . max,
309
+ omittingEmptySubsequences: Bool = true
310
+ ) -> [ SubSequence ] where C. Element == Element {
311
+ Array ( split ( by: ZSearcher ( pattern: Array ( separator) , by: == ) , maxSplits: maxSplits, omittingEmptySubsequences: omittingEmptySubsequences) )
254
312
}
255
313
}
256
314
@@ -267,12 +325,15 @@ extension BidirectionalCollection where Element: Equatable {
267
325
268
326
extension BidirectionalCollection where Element: Comparable {
269
327
func split< C: Collection > (
270
- by separator: C
328
+ by separator: C ,
329
+ maxSplits: Int ,
330
+ omittingEmptySubsequences: Bool
271
331
) -> SplitCollection < PatternOrEmpty < TwoWaySearcher < Self > > >
272
332
where C. Element == Element
273
333
{
274
334
split (
275
- by: PatternOrEmpty ( searcher: TwoWaySearcher ( pattern: Array ( separator) ) ) )
335
+ by: PatternOrEmpty ( searcher: TwoWaySearcher ( pattern: Array ( separator) ) ) ,
336
+ maxSplits: maxSplits, omittingEmptySubsequences: omittingEmptySubsequences)
276
337
}
277
338
278
339
// FIXME
@@ -292,9 +353,11 @@ extension BidirectionalCollection where Element: Comparable {
292
353
extension BidirectionalCollection where SubSequence == Substring {
293
354
@_disfavoredOverload
294
355
func split< R: RegexComponent > (
295
- by separator: R
356
+ by separator: R ,
357
+ maxSplits: Int ,
358
+ omittingEmptySubsequences: Bool
296
359
) -> SplitCollection < RegexConsumer < R , Self > > {
297
- split ( by: RegexConsumer ( separator) )
360
+ split ( by: RegexConsumer ( separator) , maxSplits : maxSplits , omittingEmptySubsequences : omittingEmptySubsequences )
298
361
}
299
362
300
363
func splitFromBack< R: RegexComponent > (
@@ -303,15 +366,22 @@ extension BidirectionalCollection where SubSequence == Substring {
303
366
splitFromBack ( by: RegexConsumer ( separator) )
304
367
}
305
368
306
- // FIXME: Return `some Collection<Substring>` for SE-0346
369
+ // TODO: Is this @_disfavoredOverload necessary?
370
+ // It prevents split(separator: String) from choosing this overload instead
371
+ // of the collection-based version when String has RegexComponent conformance
372
+
373
+ // FIXME: Return `some Collection<Subsequence>` for SE-0346
307
374
/// Returns the longest possible subsequences of the collection, in order,
308
375
/// around elements equal to the given separator.
309
376
/// - Parameter separator: A regex describing elements to be split upon.
310
377
/// - Returns: A collection of substrings, split from this collection's
311
378
/// elements.
379
+ @_disfavoredOverload
312
380
public func split< R: RegexComponent > (
313
- by separator: R
381
+ separator: R ,
382
+ maxSplits: Int = . max,
383
+ omittingEmptySubsequences: Bool = true
314
384
) -> [ SubSequence ] {
315
- Array ( split ( by: RegexConsumer ( separator) ) )
385
+ Array ( split ( by: RegexConsumer ( separator) , maxSplits : maxSplits , omittingEmptySubsequences : omittingEmptySubsequences ) )
316
386
}
317
387
}
0 commit comments