Implement handling of allowEmptySlices, add LazyCollectionType.split .

Proper unit tests, also of standard library CollectionType.split, to ensure they do the same.
This commit is contained in:
Kare Morstol
2015-12-10 03:00:12 +01:00
parent 0768a86420
commit d55ddf0fb7
2 changed files with 78 additions and 19 deletions
+20 -6
View File
@@ -5,29 +5,43 @@
*
*/
public struct LazySplitGenerator <Base: CollectionType where Base.Generator.Element: Equatable, Base.SubSequence: CollectionType,
Base.SubSequence.Generator.Element==Base.Generator.Element, Base.SubSequence==Base.SubSequence.SubSequence>: GeneratorType {
public struct LazySplitSequence <Base: CollectionType where Base.Generator.Element: Equatable, Base.SubSequence: CollectionType,
Base.SubSequence.Generator.Element==Base.Generator.Element, Base.SubSequence==Base.SubSequence.SubSequence>: GeneratorType, LazySequenceType {
private var remaining: Base.SubSequence?
private let separator: Base.Generator.Element
private let allowEmptySlices: Bool
public init (base: Base, separator: Base.Generator.Element) {
public init (base: Base, separator: Base.Generator.Element, allowEmptySlices: Bool = false) {
self.separator = separator
self.remaining = base[base.startIndex..<base.endIndex]
self.allowEmptySlices = allowEmptySlices
}
public mutating func next() -> Base.SubSequence? {
guard let remaining = self.remaining else { return nil }
let (head,tail) = remaining.splitOnce(separator)
let (head,tail) = remaining.splitOnce(separator, allowEmptySlices: allowEmptySlices)
self.remaining = tail
return head
}
public func generate() -> LazySplitSequence { return self }
}
extension CollectionType where Generator.Element: Equatable {
extension CollectionType where Generator.Element: Equatable, SubSequence: CollectionType, SubSequence.Generator.Element==Generator.Element, SubSequence==SubSequence.SubSequence {
public func splitOnce (separator: Generator.Element, allowEmptySlices: Bool = false) -> (head: SubSequence, tail: SubSequence?) {
guard let nextindex = indexOf(separator) else { return (self[startIndex..<endIndex], nil) }
return (self[startIndex..<nextindex], self[nextindex.successor()..<endIndex])
let head = self[startIndex..<nextindex]
let tail = self[nextindex.successor()..<endIndex]
if !allowEmptySlices && head.isEmpty { return tail.splitOnce(separator, allowEmptySlices: false) }
return (head, tail.isEmpty && !allowEmptySlices ? nil : tail)
}
}
extension LazyCollectionType where Elements.Generator.Element: Equatable, Elements.SubSequence: CollectionType, Elements.SubSequence.Generator.Element==Elements.Generator.Element, Elements.SubSequence==Elements.SubSequence.SubSequence {
public func split (separator: Self.Elements.Generator.Element, allowEmptySlices: Bool = false) -> LazySplitSequence<Self.Elements> {
return LazySplitSequence(base: self.elements, separator: separator, allowEmptySlices: allowEmptySlices)
}
}
+58 -13
View File
@@ -11,24 +11,69 @@ import XCTest
class LazySplitGenerator_Tests: XCTestCase {
func splitToArray (s: String) -> [String] {
let g = LazySplitGenerator(base: s.characters, separator: " " as Character)
return AnySequence {g} .map {String($0)}
func lazySplitToArray (allowEmptySlices allowEmptySlices: Bool) (_ s: String) -> [String] {
let seq: LazySplitSequence = s.characters.lazy.split("," as Character, allowEmptySlices: allowEmptySlices)
return seq.map {String($0)}
}
func testStrings () {
XCTAssertEqual(splitToArray("abc def"), ["abc","def"])
XCTAssertEqual(splitToArray(" a"), ["","a"])
XCTAssertEqual(splitToArray("a "), ["a",""])
XCTAssertEqual(splitToArray("a b"), ["a","","b"])
func testStringsLazySplit_AllowingEmptySlices () {
let split = lazySplitToArray(allowEmptySlices: true)
XCTAssertEqual(split("ab,c,de,f"), ["ab","c","de","f"])
XCTAssertEqual(split(",a"), ["","a"])
XCTAssertEqual(split("a,"), ["a",""])
XCTAssertEqual(split("a,,b,,,c"), ["a","","b","","","c"])
XCTAssertEqual(split(""), [""])
XCTAssertEqual(split(","), ["",""])
XCTAssertEqual(split("ab"), ["ab"])
}
func splitIntsToArray (s: [Int]) -> [[Int]] {
let g = LazySplitGenerator(base: s, separator: 0)
return AnySequence {g} .map {Array($0)}
func testCollectionTypeSplit_AllowingEmptySlices () {
let split = {(s: String) -> [String] in
s.characters.split(",", allowEmptySlices: true).map {String($0)}
}
XCTAssertEqual(split("ab,c,de,f"), ["ab","c","de","f"])
XCTAssertEqual(split(",a"), ["","a"])
XCTAssertEqual(split("a,"), ["a",""])
XCTAssertEqual(split("a,,b,,,c"), ["a","","b","","","c"])
XCTAssertEqual(split(""), [""])
XCTAssertEqual(split(","), ["",""])
XCTAssertEqual(split("ab"), ["ab"])
}
func testInts () {
XCTAssertEqual(splitIntsToArray([1,2,0,4,0,6,7,8,9]), [[1,2],[4],[6,7,8,9]])
func testStringsLazySplit_NoEmptySlices () {
let split = lazySplitToArray(allowEmptySlices: false)
XCTAssertEqual(split("ab,c,de,f"), ["ab","c","de","f"])
XCTAssertEqual(split(",a"), ["a"])
XCTAssertEqual(split("a,"), ["a"])
XCTAssertEqual(split("a,,b,,,c"), ["a","b","c"])
XCTAssertEqual(split(""), [])
XCTAssertEqual(split(","), [])
XCTAssertEqual(split("ab"), ["ab"])
}
func testCollectionTypeSplit_NoEmptySlices () {
let split = {(s: String) -> [String] in
s.characters.split(",", allowEmptySlices: false).map {String($0)}
}
XCTAssertEqual(split("ab,c,de,f"), ["ab","c","de","f"])
XCTAssertEqual(split(",a"), ["a"])
XCTAssertEqual(split("a,"), ["a"])
XCTAssertEqual(split("a,,b,,,c"), ["a","b","c"])
XCTAssertEqual(split(""), [])
XCTAssertEqual(split(","), [])
XCTAssertEqual(split("ab"), ["ab"])
}
func testIntsLazySplit_NoEmptySlices () {
let split = {(s: [Int]) -> [[Int]] in
s.lazy.split(0, allowEmptySlices: false).map {Array($0)}
}
XCTAssertEqual(split([1,2,0,4,0,6,7,8,9]), [[1,2],[4],[6,7,8,9]])
}
}