// -*- swift -*- // RUN: rm -rf %t ; mkdir -p %t // RUN: %S/../../utils/gyb %s -o %t/Algorithm.swift // RUN: %S/../../utils/line-directive %t/Algorithm.swift -- %target-build-swift %t/Algorithm.swift -o %t/a.out // RUN: %S/../../utils/line-directive %t/Algorithm.swift -- %target-run %t/a.out import StdlibUnittest import SwiftPrivate var Algorithm = TestSuite("Algorithm") // FIXME(prext): remove this conformance. extension String.UnicodeScalarView : Equatable {} // FIXME(prext): remove this function. public func == ( lhs: String.UnicodeScalarView, rhs: String.UnicodeScalarView) -> Bool { return Array(lhs) == Array(rhs) } Algorithm.test("split") { expectEqual( [ "foo", " bar baz " ].map { $0.unicodeScalars }, split(" foo bar baz ".unicodeScalars, maxSplit: 1) { $0._isSpace() }) expectEqual( [ "foo", "bar", "baz" ].map { $0.unicodeScalars }, split( " foo bar baz ".unicodeScalars, allowEmptySlices: false) { $0._isSpace() }) expectEqual( [ "", "", "foo", "", "", "bar", "baz", "" ].map { $0.unicodeScalars }, split( " foo bar baz ".unicodeScalars, allowEmptySlices: true) { $0._isSpace() }) expectEqual( [ "", "", "foo bar baz " ].map { $0.unicodeScalars }, split( " foo bar baz ".unicodeScalars, allowEmptySlices: true, maxSplit: 2, isSeparator: { $0._isSpace() })) } // FIXME(prext): move this struct to the point of use. struct StartsWithTest { let expected: Bool let sequence: [Int] let prefix: [Int] let expectedLeftoverSequence: [Int] let expectedLeftoverPrefix: [Int] let loc: SourceLoc init( _ expected: Bool, _ sequence: [Int], _ prefix: [Int], _ expectedLeftoverSequence: [Int], _ expectedLeftoverPrefix: [Int], file: String = __FILE__, line: UWord = __LINE__ ) { self.expected = expected self.sequence = sequence self.prefix = prefix self.expectedLeftoverSequence = expectedLeftoverSequence self.expectedLeftoverPrefix = expectedLeftoverPrefix self.loc = SourceLoc(file, line, comment: "test data") } } let startsWithTests = [ // Corner cases. StartsWithTest(true, [], [], [], []), StartsWithTest(false, [], [ 1 ], [], []), StartsWithTest(true, [ 1 ], [], [], []), // Equal sequences. StartsWithTest(true, [ 1 ], [ 1 ], [], []), StartsWithTest(true, [ 1, 2 ], [ 1, 2 ], [], []), // Proper prefix. StartsWithTest(true, [ 0, 1, 2 ], [ 0, 1 ], [], []), StartsWithTest(false, [ 0, 1 ], [ 0, 1, 2 ], [], []), StartsWithTest(true, [ 1, 2, 3, 4 ], [ 1, 2 ], [ 4 ], []), StartsWithTest(false, [ 1, 2 ], [ 1, 2, 3, 4 ], [], [ 4 ]), // Not a prefix. StartsWithTest(false, [ 1, 2, 3, 4 ], [ 1, 2, 10 ], [ 4 ], []), StartsWithTest(false, [ 1, 2, 10 ], [ 1, 2, 3, 4 ], [], [ 4 ]), StartsWithTest(false, [ 1, 2, 3, 4, 10 ], [ 1, 2, 10 ], [ 4, 10 ], []), StartsWithTest(false, [ 1, 2, 10 ], [ 1, 2, 3, 4, 10 ], [], [ 4, 10 ]), ] Algorithm.test("min,max") { expectEqual(2, min(3, 2)) expectEqual(3, min(3, 7, 5)) expectEqual(3, max(3, 2)) expectEqual(7, max(3, 7, 5)) // FIXME: add tests that check that min/max return the // first element of the sequence (by reference equailty) that satisfy the // condition. } Algorithm.test("filter/SequenceType") { // FIXME(prext): remove these tests together with the filter() function when // protocol extensions land. These tests have been migrated to the new API. if true { let s = MinimalSequence([], underestimatedCount: .Precise) var result = filter(s) { (x: Int) -> Bool in expectUnreachable() return true } expectType([Int].self, &result) expectEqual([], result) expectEqual([], Array(s)) { "sequence should be consumed" } expectEqual(0, result.capacity) } if true { let s = MinimalSequence( [ 0, 30, 10, 90 ], underestimatedCount: .Value(0)) let result = filter(s) { (x: Int) -> Bool in false } expectEqual([], result) expectEqual([], Array(s)) { "sequence should be consumed" } expectEqual(0, result.capacity) } if true { let s = MinimalSequence( [ 0, 30, 10, 90 ], underestimatedCount: .Value(0)) let result = filter(s) { (x: Int) -> Bool in true } expectEqual([ 0, 30, 10, 90 ], result) expectEqual([], Array(s)) { "sequence should be consumed" } expectGE(2 * result.count, result.capacity) } if true { let s = MinimalSequence( [ 0, 30, 10, 90 ], underestimatedCount: .Value(0)) let result = filter(s) { $0 % 3 == 0 } expectEqual([ 0, 30, 90 ], result) expectEqual([], Array(s)) { "sequence should be consumed" } expectGE(2 * result.count, result.capacity) } if true { let s = MinimalSequence( [ 0, 30, 10, 90 ], underestimatedCount: .Precise) let result = filter(s) { $0 % 3 == 0 } expectEqual([ 0, 30, 90 ], result) expectEqual([], Array(s)) { "sequence should be consumed" } expectGE(2 * result.count, result.capacity) } } Algorithm.test("filter/CollectionType") { // FIXME(prext): remove these tests together with the filter() function when // protocol extensions land. These tests have been migrated to the new API. if true { let c = MinimalForwardCollection([]) var result = filter(c) { (x: Int) -> Bool in expectUnreachable() return true } expectEqual([], result) expectType([Int].self, &result) expectEqual(0, result.capacity) } if true { let c = MinimalForwardCollection([ 0, 30, 10, 90 ]) let result = filter(c) { (x: Int) -> Bool in false } expectEqual([], result) expectEqual(0, result.capacity) } if true { let c = MinimalForwardCollection([ 0, 30, 10, 90 ]) let result = filter(c) { (x: Int) -> Bool in true } expectEqual([ 0, 30, 10, 90 ], result) expectGE(2 * result.count, result.capacity) } if true { let c = MinimalForwardCollection([ 0, 30, 10, 90 ]) let result = filter(c) { $0 % 3 == 0 } expectEqual([ 0, 30, 90 ], result) expectGE(2 * result.count, result.capacity) } } Algorithm.test("filter/eager") { // Make sure filter is eager and only calls its predicate once per element. // FIXME(prext): remove these tests together with the filter() function when // protocol extensions land. These tests have been migrated to the new API. var count = 0 let one = filter(0..<10) { (x: Int)->Bool in ++count; return x == 1 } for x in one {} expectEqual(10, count) for x in one {} expectEqual(10, count) } Algorithm.test("map/SequenceType") { // FIXME(prext): remove these tests together with the map() function when // protocol extensions land. These tests have been migrated to the new API. if true { let s = MinimalSequence([], underestimatedCount: .Precise) var result = map(s) { (x: Int) -> Int16 in expectUnreachable() return 42 } expectType([Int16].self, &result) expectEqual([], result) expectEqual([], Array(s)) } if true { let s = MinimalSequence( [ 0, 30, 10, 90 ], underestimatedCount: .Value(0)) let result = map(s) { $0 + 1 } expectEqual([ 1, 31, 11, 91 ], result) expectEqual([], Array(s)) } if true { let s = MinimalSequence( [ 0, 30, 10, 90 ], underestimatedCount: .Precise) let result = map(s) { $0 + 1 } expectEqual([ 1, 31, 11, 91 ], result) expectEqual([], Array(s)) } } Algorithm.test("map/CollectionType") { // FIXME(prext): remove these tests together with the map() function when // protocol extensions land. These tests have been migrated to the new API. if true { let c = MinimalForwardCollection([]) var result = map(c) { (x: Int) -> Int16 in expectUnreachable() return 42 } expectType([Int16].self, &result) expectEqual([], result) expectLE(c.underestimatedCount, result.capacity) } if true { let c = MinimalForwardCollection( [ 0, 30, 10, 90 ], underestimatedCount: .Value(0)) let result = map(c) { $0 + 1 } expectEqual([ 1, 31, 11, 91 ], result) } } Algorithm.test("sorted/strings") .xfail(.LinuxAny(reason: "String comparison: ICU vs. Foundation")) .code { expectEqual( [ "Banana", "apple", "cherry" ], sorted([ "apple", "Banana", "cherry" ])) let s = sorted(["apple", "Banana", "cherry"]) { $0.characters.count() > $1.characters.count() } expectEqual([ "Banana", "cherry", "apple" ], s) } // A wrapper around Array that disables any type-specific algorithm // optimizations and forces bounds checking on. struct A : MutableSliceable { init(_ a: Array) { impl = a } var startIndex: Int { return 0 } var endIndex: Int { return impl.count } func generate() -> Array.Generator { return impl.generate() } subscript(i: Int) -> T { get { expectTrue(i >= 0 && i < impl.count) return impl[i] } set (x) { expectTrue(i >= 0 && i < impl.count) impl[i] = x } } subscript(r: Range) -> Array.SubSlice { get { expectTrue(r.startIndex >= 0 && r.startIndex <= impl.count) expectTrue(r.endIndex >= 0 && r.endIndex <= impl.count) return impl[r] } set (x) { expectTrue(r.startIndex >= 0 && r.startIndex <= impl.count) expectTrue(r.endIndex >= 0 && r.endIndex <= impl.count) impl[r] = x } } var impl: Array } func withInvalidOrderings(body: ((Int,Int)->Bool)->Void) { // Test some ordering predicates that don't create strict weak orderings body { (_,_) in true } body { (_,_) in false } var i = 0 body { (_,_) in i++ % 2 == 0 } body { (_,_) in i++ % 3 == 0 } body { (_,_) in i++ % 5 == 0 } } func randomArray() -> A { let count = Int(rand32(exclusiveUpperBound: 50)) return A(randArray(count)) } Algorithm.test("invalidOrderings") { withInvalidOrderings { var a = randomArray() sort(&a, $0) } withInvalidOrderings { var a: A a = randomArray() partition(&a, a.indices, $0) } /* // FIXME: Disabled due to Unimplemented: // abstraction difference in l-value withInvalidOrderings { var a = randomArray() var pred = $0 _insertionSort(&a, a.indices, &pred) } */ } // The routine is based on http://www.cs.dartmouth.edu/~doug/mdmspe.pdf func makeQSortKiller(len: Int) -> [Int] { var candidate: Int = 0 var keys = [Int:Int]() func Compare(x: Int, y : Int) -> Bool { if keys[x] == nil && keys[y] == nil { if (x == candidate) { keys[x] = keys.count } else { keys[y] = keys.count } } if keys[x] == nil { candidate = x return true } if keys[y] == nil { candidate = y return false } return keys[x]! > keys[y]! } var ary = [Int](count: len, repeatedValue:0) var ret = [Int](count: len, repeatedValue:0) for i in 0..) func compareElements(lhs: Element, rhs: Element) -> Bool { return lhs.0 == rhs.0 && lhs.1.value == rhs.1.value } for test in enumerateTests { let s = MinimalSequence>( test.sequence._prext_map { OpaqueValue($0) }) var result = s.enumerate() expectType( EnumerateSequence>>.self, &result) checkSequence( test.expected._prext_map { (index: $0.0, element: OpaqueValue($0.1)) } as [Element], result, compareElements, resiliencyChecks: .none, test.loc.withCurrentLoc()) expectEqual([], s._prext_map { $0.value }) { "sequence should be consumed" } } } //===----------------------------------------------------------------------===// // minElement(), maxElement() //===----------------------------------------------------------------------===// struct MinMaxElementTest { let expectedMinValue: Int? let expectedMinIndex: Int? let expectedMaxValue: Int? let expectedMaxIndex: Int? let sequence: [Int] let loc: SourceLoc init( minValue expectedMinValue: Int?, index expectedMinIndex: Int?, maxValue expectedMaxValue: Int?, index expectedMaxIndex: Int?, _ sequence: [Int], file: String = __FILE__, line: UWord = __LINE__, comment: String = "" ) { self.expectedMinValue = expectedMinValue self.expectedMinIndex = expectedMinIndex self.expectedMaxValue = expectedMaxValue self.expectedMaxIndex = expectedMaxIndex self.sequence = sequence self.loc = SourceLoc(file, line, comment: "test data" + comment) } } let minMaxElementTests = [ MinMaxElementTest( minValue: nil, index: nil, maxValue: nil, index: nil, []), MinMaxElementTest( minValue: 42, index: 0, maxValue: 42, index: 0, [ 42 ]), MinMaxElementTest( minValue: -1, index: 1, maxValue: 30, index: 2, [ 10, -1, 30, -1, 30 ]), MinMaxElementTest( minValue: -2, index: 5, maxValue: 31, index: 6, [ 10, -1, 30, -1, 30, -2, 31 ]), ] % for algorithmKind in [ 'min', 'max' ]: % AlgorithmKind = algorithmKind.capitalize() SequenceTypeAlgorithms.test("${algorithmKind}Element/WhereElementIsComparable") { for test in minMaxElementTests { let s = MinimalSequence( test.sequence.enumerate()._prext_map { MinimalComparableValue($1, identity: $0) }) var maybeResult = s.${algorithmKind}Element() expectType(Optional.self, &maybeResult) if let result = maybeResult { expectEqual( test.expected${AlgorithmKind}Value!, result.value, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expected${AlgorithmKind}Index!, result.identity, stackTrace: test.loc.withCurrentLoc()) } else { expectEmpty( test.expected${AlgorithmKind}Value, stackTrace: test.loc.withCurrentLoc()) expectEmpty( test.expected${AlgorithmKind}Index, stackTrace: test.loc.withCurrentLoc()) } expectEqual([], s._prext_map { $0.value }) { "sequence should be consumed" } } } SequenceTypeAlgorithms.test("${algorithmKind}Element/Predicate") { for test in minMaxElementTests { let s = MinimalSequence>( test.sequence.enumerate()._prext_map { OpaqueValue($1, identity: $0) }) var timesClosureWasCalled = 0 var maybeResult = s.${algorithmKind}Element { (lhs, rhs) -> Bool in ++timesClosureWasCalled return lhs.value < rhs.value } expectType(Optional>.self, &maybeResult) if let result = maybeResult { expectEqual( test.expected${AlgorithmKind}Value!, result.value, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expected${AlgorithmKind}Index!, result.identity, stackTrace: test.loc.withCurrentLoc()) } else { expectEmpty( test.expected${AlgorithmKind}Value, stackTrace: test.loc.withCurrentLoc()) expectEmpty( test.expected${AlgorithmKind}Index, stackTrace: test.loc.withCurrentLoc()) } expectEqual([], s._prext_map { $0.value }) { "sequence should be consumed" } expectEqual(max(0, test.sequence.count - 1), timesClosureWasCalled) { "maxElement() should be eager and should only call its predicate once per element" } } } % end //===----------------------------------------------------------------------===// // startsWith() //===----------------------------------------------------------------------===// SequenceTypeAlgorithms.test("startsWith/WhereElementIsEquatable") { for test in startsWithTests { if true { let s = MinimalSequence( test.sequence.map { MinimalEquatableValue($0) }) let prefix = MinimalSequence( test.prefix.map { MinimalEquatableValue($0) }) expectEqual( test.expected, s.startsWith(prefix), stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverSequence, s._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverPrefix, prefix._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) } // Use different types for the sequence and prefix. if true { let s = MinimalForwardCollection( test.sequence.map { MinimalEquatableValue($0) }) let prefix = MinimalSequence( test.prefix.map { MinimalEquatableValue($0) }) expectEqual( test.expected, s.startsWith(prefix), stackTrace: test.loc.withCurrentLoc()) expectEqual( test.sequence, s._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverPrefix, prefix._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) } } } SequenceTypeAlgorithms.test("startsWith/Predicate") { for test in startsWithTests { if true { let s = MinimalSequence>( map(test.sequence) { OpaqueValue($0) }) let prefix = MinimalSequence>( map(test.prefix) { OpaqueValue($0) }) expectEqual( test.expected, s.startsWith(prefix) { $0.value == $1.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverSequence, s._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverPrefix, prefix._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) } if true { let s = MinimalSequence>( map(test.sequence) { OpaqueValue($0 * 2) }) let prefix = MinimalSequence>( map(test.prefix) { OpaqueValue($0) }) expectEqual( test.expected, s.startsWith(prefix) { $0.value / 2 == $1.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverSequence, s._prext_map { $0.value / 2 }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverPrefix, prefix._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) } // Use different types for the sequence and prefix. if true { let s = MinimalForwardCollection>( map(test.sequence) { OpaqueValue($0) }) let prefix = MinimalSequence>( map(test.prefix) { OpaqueValue($0) }) expectEqual( test.expected, s.startsWith(prefix) { $0.value == $1.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.sequence, s._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverPrefix, prefix._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) } } } //===----------------------------------------------------------------------===// // equal() //===----------------------------------------------------------------------===// struct ElementsEqualTest { let expected: Bool let sequence: [Int] let other: [Int] let expectedLeftoverSequence: [Int] let expectedLeftoverOther: [Int] let loc: SourceLoc init( _ expected: Bool, _ sequence: [Int], _ other: [Int], _ expectedLeftoverSequence: [Int], _ expectedLeftoverOther: [Int], file: String = __FILE__, line: UWord = __LINE__, comment: String = "" ) { self.expected = expected self.sequence = sequence self.other = other self.expectedLeftoverSequence = expectedLeftoverSequence self.expectedLeftoverOther = expectedLeftoverOther self.loc = SourceLoc(file, line, comment: "test data" + comment) } func flip() -> ElementsEqualTest { return ElementsEqualTest( expected, other, sequence, expectedLeftoverOther, expectedLeftoverSequence, file: loc.file, line: loc.line, comment: " (flipped)") } } let elementsEqualTests: [ElementsEqualTest] = [ ElementsEqualTest(true, [], [], [], []), ElementsEqualTest(false, [ 1 ], [], [], []), ElementsEqualTest(false, [], [ 1 ], [], []), ElementsEqualTest(false, [ 1, 2 ], [], [ 2 ], []), ElementsEqualTest(false, [], [ 1, 2 ], [], [ 2 ]), ElementsEqualTest(false, [ 1, 2, 3, 4 ], [ 1, 2 ], [ 4 ], []), ElementsEqualTest(false, [ 1, 2 ], [ 1, 2, 3, 4 ], [], [ 4 ]), ].flatMap { [ $0, $0.flip() ] } SequenceTypeAlgorithms.test("elementsEqual/WhereElementIsEquatable") { for test in elementsEqualTests { if true { let s = MinimalSequence( test.sequence.map { MinimalEquatableValue($0) }) let other = MinimalSequence( test.other.map { MinimalEquatableValue($0) }) expectEqual( test.expected, s.elementsEqual(other), stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverSequence, s._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverOther, other._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) } // Use different types for the sequence and other. if true { let s = MinimalForwardCollection( test.sequence.map { MinimalEquatableValue($0) }) let other = MinimalSequence( test.other.map { MinimalEquatableValue($0) }) expectEqual( test.expected, s.elementsEqual(other), stackTrace: test.loc.withCurrentLoc()) expectEqual( test.sequence, s._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverOther, other._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) } } } SequenceTypeAlgorithms.test("elementsEqual/Predicate") { for test in elementsEqualTests { if true { let s = MinimalSequence>( test.sequence.map { OpaqueValue($0) }) let other = MinimalSequence>( test.other.map { OpaqueValue($0) }) expectEqual( test.expected, s.elementsEqual(other) { $0.value == $1.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverSequence, s._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverOther, other._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) } // Use different types for the sequence and other. if true { let s = MinimalForwardCollection>( test.sequence.map { OpaqueValue($0) }) let other = MinimalSequence>( test.other.map { OpaqueValue($0) }) expectEqual( test.expected, s.elementsEqual(other) { $0.value == $1.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.sequence, s._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverOther, other._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) } } } //===----------------------------------------------------------------------===// // lexicographicalCompare() //===----------------------------------------------------------------------===// struct LexicographicalCompareTest { let expected: ExpectedComparisonResult let sequence: [Int] let other: [Int] let expectedLeftoverSequence: [Int] let expectedLeftoverOther: [Int] let loc: SourceLoc init( _ expected: ExpectedComparisonResult, _ sequence: [Int], _ other: [Int], _ expectedLeftoverSequence: [Int], _ expectedLeftoverOther: [Int], file: String = __FILE__, line: UWord = __LINE__, comment: String = "" ) { self.expected = expected self.sequence = sequence self.other = other self.expectedLeftoverSequence = expectedLeftoverSequence self.expectedLeftoverOther = expectedLeftoverOther self.loc = SourceLoc(file, line, comment: "test data" + comment) } func flip() -> LexicographicalCompareTest { return LexicographicalCompareTest( expected.flip(), other, sequence, expectedLeftoverOther, expectedLeftoverSequence, file: loc.file, line: loc.line, comment: " (flipped)") } } let lexicographicalCompareTests = [ LexicographicalCompareTest(.EQ, [], [], [], []), LexicographicalCompareTest(.EQ, [ 1 ], [ 1 ], [], []), LexicographicalCompareTest(.GT, [ 1 ], [], [], []), LexicographicalCompareTest(.GT, [ 1 ], [ 0 ], [], []), LexicographicalCompareTest(.EQ, [ 1 ], [ 1 ], [], []), LexicographicalCompareTest(.LT, [ 1 ], [ 2 ], [], []), LexicographicalCompareTest(.GT, [ 1, 2 ], [], [ 2 ], []), LexicographicalCompareTest(.GT, [ 1, 2 ], [ 0 ], [ 2 ], []), LexicographicalCompareTest(.GT, [ 1, 2 ], [ 1 ], [], []), LexicographicalCompareTest(.LT, [ 1, 2 ], [ 2 ], [ 2 ], []), LexicographicalCompareTest(.GT, [ 1, 2 ], [ 0, 0 ], [ 2 ], [ 0 ]), LexicographicalCompareTest(.GT, [ 1, 2 ], [ 1, 0 ], [], []), LexicographicalCompareTest(.LT, [ 1, 2 ], [ 2, 0 ], [ 2 ], [ 0 ]), LexicographicalCompareTest(.GT, [ 1, 2 ], [ 0, 1 ], [ 2 ], [ 1 ]), LexicographicalCompareTest(.GT, [ 1, 2 ], [ 1, 1 ], [], []), LexicographicalCompareTest(.LT, [ 1, 2 ], [ 2, 1 ], [ 2 ], [ 1 ]), LexicographicalCompareTest(.GT, [ 1, 2 ], [ 0, 2 ], [ 2 ], [ 2 ]), LexicographicalCompareTest(.EQ, [ 1, 2 ], [ 1, 2 ], [], []), LexicographicalCompareTest(.LT, [ 1, 2 ], [ 2, 2 ], [ 2 ], [ 2 ]), LexicographicalCompareTest(.GT, [ 1, 2 ], [ 0, 3 ], [ 2 ], [ 3 ]), LexicographicalCompareTest(.LT, [ 1, 2 ], [ 1, 3 ], [], []), LexicographicalCompareTest(.LT, [ 1, 2 ], [ 2, 3 ], [ 2 ], [ 3 ]), ].flatMap { [ $0, $0.flip() ] } SequenceTypeAlgorithms.test("lexicographicalCompare/WhereElementIsComparable") { for test in lexicographicalCompareTests { if true { let s = MinimalSequence( test.sequence.map { MinimalComparableValue($0) }) let other = MinimalSequence( test.other.map { MinimalComparableValue($0) }) expectEqual( test.expected.isLT(), s.lexicographicalCompare(other), stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverSequence, s._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverOther, other._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) } // Use different types for the sequence and other. if true { let s = MinimalForwardCollection( test.sequence.map { MinimalComparableValue($0) }) let other = MinimalSequence( test.other.map { MinimalComparableValue($0) }) expectEqual( test.expected.isLT(), s.lexicographicalCompare(other), stackTrace: test.loc.withCurrentLoc()) expectEqual( test.sequence, s._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverOther, other._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) } } } SequenceTypeAlgorithms.test("lexicographicalCompare/Predicate") { for test in lexicographicalCompareTests { if true { let s = MinimalSequence>( test.sequence.map { OpaqueValue($0) }) let other = MinimalSequence>( test.other.map { OpaqueValue($0) }) expectEqual( test.expected.isLT(), s.lexicographicalCompare(other) { $0.value < $1.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverSequence, s._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverOther, other._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) } // Use different types for the sequence and other. if true { let s = MinimalForwardCollection>( test.sequence.map { OpaqueValue($0) }) let other = MinimalSequence>( test.other.map { OpaqueValue($0) }) expectEqual( test.expected.isLT(), s.lexicographicalCompare(other) { $0.value < $1.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.sequence, s._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverOther, other._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) } } } //===----------------------------------------------------------------------===// // contains() //===----------------------------------------------------------------------===// // These tests are shared between find() and contains(). struct FindTest { let expected: Int? let element: Int let sequence: [Int] let expectedLeftoverSequence: [Int] let loc: SourceLoc init( _ expected: Int?, _ element: Int, _ sequence: [Int], _ expectedLeftoverSequence: [Int], file: String = __FILE__, line: UWord = __LINE__ ) { self.expected = expected self.element = element self.sequence = sequence self.expectedLeftoverSequence = expectedLeftoverSequence self.loc = SourceLoc(file, line, comment: "test data") } } let findTests = [ FindTest(nil, 42, [], []), FindTest(nil, 42, [ 1 ], []), FindTest(0, 1, [ 1 ], []), FindTest(nil, 42, [ 1, 2, 3, 4 ], []), FindTest(0, 1, [ 1, 2, 3, 4 ], [ 2, 3, 4 ]), FindTest(1, 2, [ 1, 2, 3, 4 ], [ 3, 4 ]), FindTest(2, 3, [ 1, 2, 3, 4 ], [ 4 ]), FindTest(3, 4, [ 1, 2, 3, 4 ], []), ] func callStaticContains( sequence: MinimalSequence, _ element: MinimalEquatableValue ) -> Bool { return sequence.contains(element) } func callGenericContains< S : SequenceType where S.Generator.Element : Equatable >(sequence: S, _ element: S.Generator.Element) -> Bool { return sequence.contains(element) } % for dispatch in [ 'Static', 'Generic' ]: SequenceTypeAlgorithms.test("contains/WhereElementIsEquatable/${dispatch}") { for test in findTests { let s = MinimalSequence( test.sequence.map { MinimalEquatableValue($0) }) expectEqual( test.expected != nil, call${dispatch}Contains(s, MinimalEquatableValue(test.element)), stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverSequence, s._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) } } % end struct SequenceWithCustomContainsMethod : SequenceType { static var timesContainsWasCalled: Int = 0 internal let _elements: [Int] init(_ elements: [Int]) { self._elements = elements } func generate() -> MinimalGenerator { // Lie from our generate() method about sequence contents. // Tests using this type should not call generate() anyway. expectUnreachable() return MinimalSequence([]).generate() } func _customContainsEquatableElement( element: MinimalEquatableValue ) -> Bool? { ++SequenceWithCustomContainsMethod.timesContainsWasCalled for e in _elements { if e == element.value { return true } } return false } } func callStaticContains( sequence: SequenceWithCustomContainsMethod, _ element: MinimalEquatableValue) -> Bool { return sequence.contains(element) } % for dispatch in [ 'Static', 'Generic' ]: SequenceTypeAlgorithms.test("contains/WhereElementIsEquatable/CustomImplementation/${dispatch}") { for test in findTests { let s = SequenceWithCustomContainsMethod(test.sequence) SequenceWithCustomContainsMethod.timesContainsWasCalled = 0 expectEqual( test.expected != nil, call${dispatch}Contains(s, MinimalEquatableValue(test.element)), stackTrace: test.loc.withCurrentLoc()) expectEqual(1, SequenceWithCustomContainsMethod.timesContainsWasCalled) } } % end func callStaticContains( set: Set, _ element: MinimalHashableValue ) -> Bool { return set.contains(element) } % for dispatch in [ 'Static', 'Generic' ]: // FIXME: implement the same optimization for Dictionary. // FIXME: move to the file where other Set tests live. SequenceTypeAlgorithms.test("Set.contains/WhereElementIsEquatable/CustomImplementation/${dispatch}") { for test in findTests { let s = Set( test.sequence.map { MinimalHashableValue($0) }) MinimalHashableValue.timesEqualEqualWasCalled = 0 MinimalHashableValue.timesHashValueWasCalled = 0 expectEqual( test.expected != nil, call${dispatch}Contains(s, MinimalHashableValue(test.element)), stackTrace: test.loc.withCurrentLoc()) if test.sequence.isEmpty { expectEqual( 0, MinimalHashableValue.timesEqualEqualWasCalled, stackTrace: test.loc.withCurrentLoc()) expectEqual( 0, MinimalHashableValue.timesHashValueWasCalled, stackTrace: test.loc.withCurrentLoc()) } else { expectNotEqual( 0, MinimalHashableValue.timesHashValueWasCalled, stackTrace: test.loc.withCurrentLoc()) } if test.expected != nil { expectNotEqual( 0, MinimalHashableValue.timesEqualEqualWasCalled, stackTrace: test.loc.withCurrentLoc()) } } } % end SequenceTypeAlgorithms.test("contains/Predicate") { for test in findTests { let s = MinimalSequence>( test.sequence.map { OpaqueValue($0) }) expectEqual( test.expected != nil, s.contains { $0.value == test.element }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverSequence, s._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) } } //===----------------------------------------------------------------------===// // reduce() //===----------------------------------------------------------------------===// struct ReduceTest { let sequence: [Int] let loc: SourceLoc init( _ sequence: [Int], file: String = __FILE__, line: UWord = __LINE__ ) { self.sequence = sequence self.loc = SourceLoc(file, line, comment: "test data") } } let reduceTests = [ ReduceTest([]), ReduceTest([ 1 ]), ReduceTest([ 1, 2 ]), ReduceTest([ 1, 2, 3 ]), ReduceTest([ 1, 2, 3, 4, 5, 6, 7 ]), ] SequenceTypeAlgorithms.test("reduce") { for test in reduceTests { let s = MinimalSequence>( test.sequence.map { OpaqueValue($0) }) var timesClosureWasCalled = 0 let result = s.reduce(OpaqueValue<[Int]>([])) { (partialResult: OpaqueValue<[Int]>, element: OpaqueValue) -> OpaqueValue<[Int]> in ++timesClosureWasCalled return OpaqueValue<[Int]>(partialResult.value + [ element.value ]) } expectEqual(test.sequence, result.value) expectEqual([], s._prext_map { $0.value }) { "sequence should be consumed" } expectEqual(test.sequence.count, timesClosureWasCalled) { "reduce() should be eager and should only call its predicate once per element" } } } //===----------------------------------------------------------------------===// // reverse() //===----------------------------------------------------------------------===// struct ReverseTest { let expected: [Int] let sequence: [Int] let loc: SourceLoc init( _ expected: [Int], _ sequence: [Int], file: String = __FILE__, line: UWord = __LINE__ ) { self.expected = expected self.sequence = sequence self.loc = SourceLoc(file, line, comment: "test data") } } let reverseTests: [ReverseTest] = [ ReverseTest([], []), ReverseTest([ 1 ], [ 1 ]), ReverseTest([ 2, 1 ], [ 1, 2 ]), ReverseTest([ 3, 2, 1 ], [ 1, 2, 3 ]), ReverseTest([ 4, 3, 2, 1 ], [ 1, 2, 3, 4]), ReverseTest( [ 7, 6, 5, 4, 3, 2, 1 ], [ 1, 2, 3, 4, 5, 6, 7 ]), ] SequenceTypeAlgorithms.test("reverse/SequenceType") { for test in reverseTests { let s = MinimalSequence>( test.sequence.map { OpaqueValue($0) }) var result = s.reverse() expectType([OpaqueValue].self, &result) expectEqual( test.expected, result.map { $0.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual([], s._prext_map { $0.value }) { "sequence should be consumed" } } } SequenceTypeAlgorithms.test("reverse/WhereIndexIsBidirectional,BidirectionalReverseView") { for test in reverseTests { let s = MinimalBidirectionalCollection>( test.sequence.map { OpaqueValue($0) }) var result = s.reverse() expectType( BidirectionalReverseView>>.self, &result) expectEqual( test.expected, result._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) // Check BidirectionalReverseView CollectionType conformance. checkBidirectionalCollection( test.expected.map { OpaqueValue($0) } as [OpaqueValue], result, { $0.value == $1.value }, test.loc.withCurrentLoc()) } } SequenceTypeAlgorithms.test("reverse/WhereIndexIsRandomAccess,RandomAccessReverseView") { for test in reverseTests { let s = MinimalRandomAccessCollection>( test.sequence.map { OpaqueValue($0) }) var result = s.reverse() expectType( RandomAccessReverseView>>.self, &result) expectEqual( test.expected, result._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) // Check RandomAccessReverseView CollectionType conformance. checkRandomAccessCollection( test.expected.map { OpaqueValue($0) } as [OpaqueValue], result, { $0.value == $1.value }, test.loc.withCurrentLoc()) } } //===----------------------------------------------------------------------===// // filter() //===----------------------------------------------------------------------===// struct FilterTest { let expected: [Int] let sequence: [Int] let includeElement: (Int) -> Bool let loc: SourceLoc init( _ expected: [Int], _ sequence: [Int], _ includeElement: (Int) -> Bool, file: String = __FILE__, line: UWord = __LINE__ ) { self.expected = expected self.sequence = sequence self.includeElement = includeElement self.loc = SourceLoc(file, line, comment: "test data") } } let filterTests = [ FilterTest( [], [], { (x: Int) -> Bool in expectUnreachable(); return true }), FilterTest([], [ 0, 30, 10, 90 ], { (x: Int) -> Bool in false }), FilterTest( [ 0, 30, 10, 90 ], [ 0, 30, 10, 90 ], { (x: Int) -> Bool in true } ), FilterTest( [ 0, 30, 90 ], [ 0, 30, 10, 90 ], { (x: Int) -> Bool in x % 3 == 0 } ), ] func callStaticSequenceFilter( sequence: MinimalSequence>, @noescape includeElement: (OpaqueValue) -> Bool ) -> [OpaqueValue] { var result = sequence._prext_filter(includeElement) expectType([OpaqueValue].self, &result) return result } func callGenericSequenceFilter( sequence: S, @noescape includeElement: (S.Generator.Element) -> Bool ) -> [S.Generator.Element] { var result = sequence._prext_filter(includeElement) expectType(Array.self, &result) return result } % for dispatch in [ 'Static', 'Generic' ]: SequenceTypeAlgorithms.test("filter/SequenceType/${dispatch}") { expectEqual(0, LifetimeTracked.instances) for test in filterTests { for underestimateCountBehavior in [ UnderestimateCountBehavior.Precise, UnderestimateCountBehavior.Half, UnderestimateCountBehavior.Value(0) ] { let s = MinimalSequence>( test.sequence.map { OpaqueValue($0) }, underestimatedCount: underestimateCountBehavior) let closureLifetimeTracker = LifetimeTracked(0) expectEqual(1, LifetimeTracked.instances) var timesClosureWasCalled = 0 var result = call${dispatch}SequenceFilter(s) { (element) in _blackHole(closureLifetimeTracker) ++timesClosureWasCalled return test.includeElement(element.value) } expectType([OpaqueValue].self, &result) expectEqual(test.expected, map(result) { $0.value }) expectEqual([], s._prext_map { $0.value }) { "sequence should be consumed" } expectEqual(test.sequence.count, timesClosureWasCalled) { "filter() should be eager and should only call its predicate once per element" } expectGE(2 * result.count, result.capacity) { "filter() should not reserve capacity (it does not know how much the predicate will filter out)" } } } expectEqual(0, LifetimeTracked.instances) } % end func callGenericCollectionFilter( collection: C, @noescape includeElement: (C.Generator.Element) -> Bool ) -> C { var result = collection._prext_filter(includeElement) expectType(C.self, &result) return result } % for Implementation in [ 'Default', 'Custom' ]: % CollectionType = 'RangeReplaceableCollectionWith%sFilterMethod' % Implementation struct ${CollectionType} : RangeReplaceableCollectionType { % if Implementation == 'Custom': static var timesFilterWasCalled = 0 % end var elements: [OpaqueValue] var reservedCapacity: Int = 0 init() { self.elements = [] } init(_ elements: [OpaqueValue]) { self.elements = elements } func generate() -> MinimalGenerator> { return MinimalSequence>(elements).generate() } var startIndex: MinimalForwardIndex { return MinimalForwardIndex( position: 0, startIndex: 0, endIndex: elements.endIndex) } var endIndex: MinimalForwardIndex { return MinimalForwardIndex( position: elements.endIndex, startIndex: 0, endIndex: elements.endIndex) } subscript(i: MinimalForwardIndex) -> OpaqueValue { return elements[i.position] } mutating func reserveCapacity(n: Int) { elements.reserveCapacity(n) reservedCapacity = max(reservedCapacity, n) } mutating func append(x: OpaqueValue) { elements.append(x) } mutating func extend< S : SequenceType where S.Generator.Element == OpaqueValue >(newElements: S) { expectUnreachable() } mutating func replaceRange< C : CollectionType where C.Generator.Element == OpaqueValue >( subRange: Range, with newElements: C ) { expectUnreachable() } mutating func insert( newElement: OpaqueValue, atIndex i: MinimalForwardIndex ) { expectUnreachable() } mutating func splice< S : CollectionType where S.Generator.Element == OpaqueValue >(newElements: S, atIndex i: MinimalForwardIndex) { expectUnreachable() } mutating func removeAtIndex(i: MinimalForwardIndex) -> OpaqueValue { expectUnreachable() return OpaqueValue(0xffff) } mutating func removeRange(subRange: Range) { expectUnreachable() } mutating func removeAll(#keepCapacity: Bool = false) { expectUnreachable() } % if Implementation == 'Custom': func _prext_filter( @noescape includeElement: (OpaqueValue) -> Bool ) -> ${CollectionType} { ++RangeReplaceableCollectionWithCustomFilterMethod.timesFilterWasCalled return ${CollectionType}(elements._prext_filter(includeElement)) } % end } % end % for (CollectionType, CollectionKind) in [ % ('MinimalForwardRangeReplaceableCollectionType>', 'Minimal'), % ('RangeReplaceableCollectionWithDefaultFilterMethod', 'DefaultImplementation'), % ('RangeReplaceableCollectionWithCustomFilterMethod', 'CustomImplementation'), % ('Array>', 'StdlibArray'), % ('ContiguousArray>', 'StdlibArray'), % ('ArraySlice>', 'StdlibArray') % ]: % for dispatch in [ 'Static', 'Generic' ]: % if dispatch == 'Static': func callStaticCollectionFilter( collection: ${CollectionType}, @noescape includeElement: (OpaqueValue) -> Bool ) -> ${CollectionType} { var result = collection._prext_filter(includeElement) expectType(${CollectionType}.self, &result) return result } % end SequenceTypeAlgorithms.test("filter/RangeReplaceableCollectionType/${CollectionType}/${dispatch}") { expectEqual(0, LifetimeTracked.instances) for test in filterTests { for underestimateCountBehavior in [ UnderestimateCountBehavior.Precise, UnderestimateCountBehavior.Half, UnderestimateCountBehavior.Value(0) ] { % if CollectionKind == 'Minimal': let s = ${CollectionType}( test.sequence.map { OpaqueValue($0) }, underestimatedCount: underestimateCountBehavior) % else: let s = ${CollectionType}( test.sequence.map { OpaqueValue($0) }) % end % if CollectionKind == 'CustomImplementation': RangeReplaceableCollectionWithCustomFilterMethod.timesFilterWasCalled = 0 % end let closureLifetimeTracker = LifetimeTracked(0) expectEqual(1, LifetimeTracked.instances) var timesClosureWasCalled = 0 var result = call${dispatch}CollectionFilter(s) { (element) in _blackHole(closureLifetimeTracker) ++timesClosureWasCalled return test.includeElement(element.value) } expectType(${CollectionType}.self, &result) expectEqual( test.expected, result._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) % if CollectionKind == 'CustomImplementation': expectEqual( 1, RangeReplaceableCollectionWithCustomFilterMethod.timesFilterWasCalled) % end expectEqual(test.sequence, s._prext_map { $0.value }) { "collection should not be consumed" } expectEqual(test.sequence.count, timesClosureWasCalled) { "filter() should be eager and should only call its predicate once per element" } expectGE(2 * result.count(), result.${'capacity' if CollectionKind == 'StdlibArray' else 'reservedCapacity'}) { "filter() should not reserve capacity (it does not know how much the predicate will filter out)" } } } expectEqual(0, LifetimeTracked.instances) } % end % end //===----------------------------------------------------------------------===// // map() //===----------------------------------------------------------------------===// struct MapTest { let expected: [Int32] let sequence: [Int] let transform: (Int) -> Int32 let loc: SourceLoc init( _ expected: [Int32], _ sequence: [Int], _ transform: (Int) -> Int32, file: String = __FILE__, line: UWord = __LINE__ ) { self.expected = expected self.sequence = sequence self.transform = transform self.loc = SourceLoc(file, line, comment: "test data") } } let mapTests = [ MapTest( [], [], { (x: Int) -> Int32 in expectUnreachable(); return 0xffff }), MapTest([ 101 ], [ 1 ], { (x: Int) -> Int32 in x + 100 }), MapTest([ 101, 102 ], [ 1, 2 ], { (x: Int) -> Int32 in x + 100 }), MapTest([ 101, 102, 103 ], [ 1, 2, 3 ], { (x: Int) -> Int32 in x + 100 }), MapTest(Array(101..<200), Array(1..<100), { (x: Int) -> Int32 in x + 100 }), ] var MinimalSequenceWithCustomMap_timesMapWasCalled: Int = 0 % for Implementation in [ 'Default', 'Custom' ]: struct MinimalSequenceWith${Implementation}Map : SequenceType { init(_ data: [Element], underestimatedCount: UnderestimateCountBehavior) { self._data = MinimalSequence( data, underestimatedCount: underestimatedCount) } func generate() -> MinimalGenerator { return _data.generate() } var _data: MinimalSequence % if Implementation == 'Custom': static var timesMapWasCalled: Int { get { return MinimalSequenceWithCustomMap_timesMapWasCalled } set { MinimalSequenceWithCustomMap_timesMapWasCalled = newValue } } func _prext_map( @noescape transform: (Element) -> T ) -> [T] { ++MinimalSequenceWithCustomMap.timesMapWasCalled return _data._prext_map(transform) } % end } % end func callStaticSequenceMap( sequence: MinimalSequenceWithDefaultMap>, @noescape transform: (OpaqueValue) -> T ) -> [T] { var result = sequence._prext_map(transform) expectType([T].self, &result) return result } func callStaticSequenceMap( sequence: MinimalSequenceWithCustomMap>, @noescape transform: (OpaqueValue) -> T ) -> [T] { var result = sequence._prext_map(transform) expectType([T].self, &result) return result } func callGenericSequenceMap( sequence: S, @noescape transform: (S.Generator.Element) -> T ) -> [T] { var result = sequence._prext_map(transform) expectType([T].self, &result) return result } % for Implementation in [ 'Default', 'Custom' ]: % for dispatch in [ 'Static', 'Generic' ]: SequenceTypeAlgorithms.test("map/SequenceType/${Implementation}Implementation/${dispatch}") { expectEqual(0, LifetimeTracked.instances) for test in mapTests { for underestimateCountBehavior in [ UnderestimateCountBehavior.Precise, UnderestimateCountBehavior.Half, UnderestimateCountBehavior.Value(0) ] { let s = MinimalSequenceWith${Implementation}Map>( test.sequence._prext_map { OpaqueValue($0) }, underestimatedCount: underestimateCountBehavior) let closureLifetimeTracker = LifetimeTracked(0) expectEqual(1, LifetimeTracked.instances) var timesClosureWasCalled = 0 % if Implementation == 'Custom': MinimalSequenceWithCustomMap>.timesMapWasCalled = 0 % end var result = call${dispatch}SequenceMap(s) { (element: OpaqueValue) -> OpaqueValue in _blackHole(closureLifetimeTracker) ++timesClosureWasCalled return OpaqueValue(Int32(test.transform(element.value))) } expectType([OpaqueValue].self, &result) expectEqual(test.expected, result._prext_map { $0.value }) % if Implementation == 'Custom': expectEqual(1, MinimalSequenceWithCustomMap>.timesMapWasCalled) % end expectEqual([], s._prext_map { $0.value }) { "sequence should be consumed" } expectEqual(test.sequence.count, timesClosureWasCalled) { "map() should be eager and should only call its predicate once per element" } } } expectEqual(0, LifetimeTracked.instances) } % end % end var MinimalForwardCollectionWithCustomMap_timesMapWasCalled: Int = 0 % for Implementation in [ 'Default', 'Custom' ]: struct MinimalForwardCollectionWith${Implementation}Map : CollectionType { init(_ data: [Element], underestimatedCount: UnderestimateCountBehavior) { self._data = MinimalForwardCollection( data, underestimatedCount: underestimatedCount) } func generate() -> MinimalGenerator { return _data.generate() } var startIndex: MinimalForwardIndex { return _data.startIndex } var endIndex: MinimalForwardIndex { return _data.endIndex } subscript(i: MinimalForwardIndex) -> Element { return _data[i] } var _data: MinimalForwardCollection % if Implementation == 'Custom': static var timesMapWasCalled: Int { get { return MinimalForwardCollectionWithCustomMap_timesMapWasCalled } set { MinimalForwardCollectionWithCustomMap_timesMapWasCalled = newValue } } func _prext_map( @noescape transform: (Element) -> T ) -> [T] { ++MinimalForwardCollectionWithCustomMap.timesMapWasCalled return _data._prext_map(transform) } % end } % end func callStaticCollectionMap( collection: MinimalForwardCollectionWithDefaultMap>, @noescape transform: (OpaqueValue) -> T ) -> [T] { var result = collection._prext_map(transform) expectType([T].self, &result) return result } func callStaticCollectionMap( collection: MinimalForwardCollectionWithCustomMap>, @noescape transform: (OpaqueValue) -> T ) -> [T] { var result = collection._prext_map(transform) expectType([T].self, &result) return result } func callGenericCollectionMap( collection: C, @noescape transform: (C.Generator.Element) -> T ) -> [T] { var result = collection._prext_map(transform) expectType([T].self, &result) return result } % for Implementation in [ 'Default', 'Custom' ]: % for dispatch in [ 'Static', 'Generic' ]: SequenceTypeAlgorithms.test("map/CollectionType/${Implementation}Implementation/${dispatch}") { expectEqual(0, LifetimeTracked.instances) for test in mapTests { for underestimateCountBehavior in [ UnderestimateCountBehavior.Precise, UnderestimateCountBehavior.Half, UnderestimateCountBehavior.Value(0) ] { let s = MinimalForwardCollectionWith${Implementation}Map>( test.sequence.map { OpaqueValue($0) }, underestimatedCount: underestimateCountBehavior) let closureLifetimeTracker = LifetimeTracked(0) expectEqual(1, LifetimeTracked.instances) var timesClosureWasCalled = 0 % if Implementation == 'Custom': MinimalForwardCollectionWithCustomMap>.timesMapWasCalled = 0 % end var result = call${dispatch}CollectionMap(s) { (element: OpaqueValue) -> OpaqueValue in _blackHole(closureLifetimeTracker) ++timesClosureWasCalled return OpaqueValue(Int32(test.transform(element.value))) } expectType([OpaqueValue].self, &result) expectEqual(test.expected, result._prext_map { $0.value }) % if Implementation == 'Custom': expectEqual(1, MinimalForwardCollectionWithCustomMap>.timesMapWasCalled) % end expectEqual(test.sequence, s._prext_map { $0.value }) { "collection should not be consumed" } expectEqual(test.sequence.count, timesClosureWasCalled) { "map() should be eager and should only call its predicate once per element" } } } expectEqual(0, LifetimeTracked.instances) } % end % end //===----------------------------------------------------------------------===// // flatMap() //===----------------------------------------------------------------------===// struct FlatMapTest { let expected: [Int32] let sequence: [Int] let transform: (Int) -> [Int32] let loc: SourceLoc init( _ expected: [Int32], _ sequence: [Int], _ transform: (Int) -> [Int32], file: String = __FILE__, line: UWord = __LINE__ ) { self.expected = expected self.sequence = sequence self.transform = transform self.loc = SourceLoc(file, line, comment: "test data") } } func flatMapTransformation(x: Int) -> [Int32] { let repetitions = x / 10 let identity = x % 10 let range = (1..<(repetitions+1)) return range.map { Int32($0 * 10 + identity) } } let flatMapTests = [ FlatMapTest( [], [], { (x: Int) -> [Int32] in expectUnreachable(); return [ 0xffff ] }), FlatMapTest([], [ 1 ], { (x: Int) -> [Int32] in [] }), FlatMapTest([], [ 1, 2 ], { (x: Int) -> [Int32] in [] }), FlatMapTest([], [ 1, 2, 3 ], { (x: Int) -> [Int32] in [] }), FlatMapTest([ 101 ], [ 1 ], { (x: Int) -> [Int32] in [ x + 100 ] }), FlatMapTest([ 101, 102 ], [ 1, 2 ], { (x: Int) -> [Int32] in [ x + 100 ] }), FlatMapTest( [ 101, 102, 103 ], [ 1, 2, 3 ], { (x: Int) -> [Int32] in [ x + 100 ] }), FlatMapTest( [ 101, 201 ], [ 1 ], { (x: Int) -> [Int32] in [ x + 100, x + 200 ] }), FlatMapTest( [ 101, 201, 102, 202 ], [ 1, 2 ], { (x: Int) -> [Int32] in [ x + 100, x + 200 ] }), FlatMapTest( [ 101, 201, 102, 202, 103, 203 ], [ 1, 2, 3 ], { (x: Int) -> [Int32] in [ x + 100, x + 200 ] }), FlatMapTest([ 11, 15 ], [ 11, 2, 3, 4, 15 ], flatMapTransformation), FlatMapTest([ 12, 13, 23 ], [ 1, 12, 23 ], flatMapTransformation), FlatMapTest( [ 11, 21, 13, 23, 33, 14 ], [ 21, 2, 33, 14 ], flatMapTransformation), ] SequenceTypeAlgorithms.test("flatMap/SequenceType") { expectEqual(0, LifetimeTracked.instances) for test in flatMapTests { for underestimateCountBehavior in [ UnderestimateCountBehavior.Precise, UnderestimateCountBehavior.Value(0) ] { let s = MinimalSequence>( test.sequence.map { OpaqueValue($0) }, underestimatedCount: underestimateCountBehavior) let closureLifetimeTracker = LifetimeTracked(0) expectEqual(1, LifetimeTracked.instances) var timesClosureWasCalled = 0 var result = s.flatMap { (element: OpaqueValue) -> MinimalSequence> in _blackHole(closureLifetimeTracker) ++timesClosureWasCalled return MinimalSequence>( test.transform(element.value).map { OpaqueValue(Int32($0)) }) } expectType([OpaqueValue].self, &result) expectEqual( test.expected, result._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual([], s._prext_map { $0.value }) { "sequence should be consumed" } expectEqual(test.sequence.count, timesClosureWasCalled) { "map() should be eager and should only call its predicate once per element" } expectGE(2 * result.count(), result.capacity) { "flatMap() should not reserve capacity" } } } expectEqual(0, LifetimeTracked.instances) } struct FlatMapToOptionalTest { let expected: [Int32] let sequence: [Int] let transform: (Int) -> Int32? let loc: SourceLoc init( _ expected: [Int32], _ sequence: [Int], _ transform: (Int) -> Int32?, file: String = __FILE__, line: UWord = __LINE__ ) { self.expected = expected self.sequence = sequence self.transform = transform self.loc = SourceLoc(file, line, comment: "test data") } } let flatMapToOptionalTests = [ FlatMapToOptionalTest( [], [], { (x: Int) -> Int32? in expectUnreachable(); return 0xffff }), FlatMapToOptionalTest([], [ 1 ], { (x: Int) -> Int32? in nil }), FlatMapToOptionalTest([], [ 1, 2 ], { (x: Int) -> Int32? in nil }), FlatMapToOptionalTest([], [ 1, 2, 3 ], { (x: Int) -> Int32? in nil }), FlatMapToOptionalTest( [ 1 ], [ 1 ], { (x: Int) -> Int32? in x > 10 ? nil : Int32(x) }), FlatMapToOptionalTest( [ 2 ], [ 11, 2, 13, 14 ], { (x: Int) -> Int32? in x > 10 ? nil : Int32(x) }), FlatMapToOptionalTest( [ 1, 4 ], [ 1, 12, 13, 4 ], { (x: Int) -> Int32? in x > 10 ? nil : Int32(x) }), FlatMapToOptionalTest( [ 1, 2, 3 ], [ 1, 2, 3 ], { (x: Int) -> Int32? in x > 10 ? nil : Int32(x) }), ] SequenceTypeAlgorithms.test("flatMap/SequenceType/TransformProducesOptional") { expectEqual(0, LifetimeTracked.instances) for test in flatMapToOptionalTests { for underestimateCountBehavior in [ UnderestimateCountBehavior.Precise, UnderestimateCountBehavior.Value(0) ] { let s = MinimalSequence>( test.sequence.map { OpaqueValue($0) }, underestimatedCount: underestimateCountBehavior) let closureLifetimeTracker = LifetimeTracked(0) expectEqual(1, LifetimeTracked.instances) var timesClosureWasCalled = 0 var result = s.flatMap { (element: OpaqueValue) -> OpaqueValue? in _blackHole(closureLifetimeTracker) ++timesClosureWasCalled return test.transform(element.value).map { OpaqueValue(Int32($0)) } } expectType([OpaqueValue].self, &result) expectEqual( test.expected, result._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual([], s._prext_map { $0.value }) { "sequence should be consumed" } expectEqual(test.sequence.count, timesClosureWasCalled) { "flatMap() should be eager and should only call its predicate once per element" } expectGE(2 * result.count(), result.capacity) { "flatMap() should not reserve capacity" } } } expectEqual(0, LifetimeTracked.instances) } //===----------------------------------------------------------------------===// // zip() //===----------------------------------------------------------------------===// struct ZipTest { let expected: [(Int, Int32)] let sequence: [Int] let other: [Int32] let expectedLeftoverSequence: [Int] let expectedLeftoverOther: [Int32] let loc: SourceLoc init( _ expected: [(Int, Int32)], sequences sequence: [Int], _ other: [Int32], leftovers expectedLeftoverSequence: [Int], _ expectedLeftoverOther: [Int32], file: String = __FILE__, line: UWord = __LINE__ ) { self.expected = expected self.sequence = sequence self.other = other self.expectedLeftoverSequence = expectedLeftoverSequence self.expectedLeftoverOther = expectedLeftoverOther self.loc = SourceLoc(file, line, comment: "test data") } } let zipTests = [ ZipTest([], sequences: [], [], leftovers: [], []), ZipTest([], sequences: [], [ 1 ], leftovers: [], [ 1 ]), ZipTest([], sequences: [], [ 1, 2 ], leftovers: [], [ 1, 2 ]), ZipTest([], sequences: [], [ 1, 2, 3 ], leftovers: [], [ 1, 2, 3 ]), ZipTest([], sequences: [ 10 ], [], leftovers: [], []), ZipTest([ (10, 1) ], sequences: [ 10 ], [ 1 ], leftovers: [], []), ZipTest([ (10, 1) ], sequences: [ 10 ], [ 1, 2 ], leftovers: [], [ 2 ]), ZipTest([ (10, 1) ], sequences: [ 10 ], [ 1, 2, 3 ], leftovers: [], [ 2, 3 ]), ZipTest( [], sequences: [ 10, 20 ], [], leftovers: [ 20 ], []), ZipTest( [ (10, 1) ], sequences: [ 10, 20 ], [ 1 ], leftovers: [], []), ZipTest( [ (10, 1), (20, 2) ], sequences: [ 10, 20 ], [ 1, 2 ], leftovers: [], []), ZipTest( [ (10, 1), (20, 2) ], sequences: [ 10, 20 ], [ 1, 2, 3 ], leftovers: [], [ 3 ]), ZipTest( [], sequences: [ 10, 20, 30 ], [], leftovers: [ 20, 30 ], []), ZipTest( [ (10, 1) ], sequences: [ 10, 20, 30 ], [ 1 ], leftovers: [ 30 ], []), ZipTest( [ (10, 1), (20, 2) ], sequences: [ 10, 20, 30 ], [ 1, 2 ], leftovers: [], []), ZipTest( [ (10, 1), (20, 2), (30, 3) ], sequences: [ 10, 20, 30 ], [ 1, 2, 3 ], leftovers: [], []), ] SequenceTypeAlgorithms.test("zip") { typealias Element = (OpaqueValue, OpaqueValue) func compareElements(lhs: Element, rhs: Element) -> Bool { return lhs.0.value == rhs.0.value && lhs.1.value == rhs.1.value } for test in zipTests { let s = MinimalSequence>( test.sequence.map { OpaqueValue($0) }) let other = MinimalSequence>( test.other.map { OpaqueValue($0) }) var result = zip(s, other) expectType( Zip2>, MinimalSequence>>.self, &result) // Check for expected result and check the Zip2 SequenceType conformance. checkSequence( test.expected._prext_map { (OpaqueValue($0), OpaqueValue($1)) }, result, compareElements, test.loc.withCurrentLoc()) // Check leftovers *after* doing checkSequence(), not before, to ensure // that checkSequence() didn't force us to consume more elements than // needed. expectEqual( test.expectedLeftoverSequence, s._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) expectEqual( test.expectedLeftoverOther, other._prext_map { $0.value }, stackTrace: test.loc.withCurrentLoc()) } } //===----------------------------------------------------------------------===// // underestimateCount() //===----------------------------------------------------------------------===// func callGenericUnderestimatedCount(s: S) -> Int { return s.underestimateCount() } struct SequenceWithDefaultUnderestimateCount : SequenceType { init() {} func generate() -> MinimalSequence>.Generator { expectUnreachable() return MinimalSequence( [ 1, 2, 3 ]._prext_map { OpaqueValue($0) } ).generate() } } SequenceTypeAlgorithms.test("underestimateCount/SequenceType/DefaultImplementation") { let s = SequenceWithDefaultUnderestimateCount() expectEqual(0, callGenericUnderestimatedCount(s)) } struct SequenceWithCustomUnderestimateCount : SequenceType { init(underestimatedCount: Int) { self._underestimatedCount = underestimatedCount } func generate() -> MinimalSequence>.Generator { expectUnreachable() return MinimalSequence( [ 0xffff, 0xffff, 0xffff ]._prext_map { OpaqueValue($0) } ).generate() } func underestimateCount() -> Int { return _underestimatedCount } let _underestimatedCount: Int } SequenceTypeAlgorithms.test("underestimateCount/SequenceType/CustomImplementation") { if true { let s = SequenceWithCustomUnderestimateCount(underestimatedCount: 5) expectEqual(5, callGenericUnderestimatedCount(s)) } if true { let s = SequenceWithCustomUnderestimateCount(underestimatedCount: 42) expectEqual(42, callGenericUnderestimatedCount(s)) } } struct CollectionWithDefaultUnderestimateCount : CollectionType { init(count: Int) { self._count = count } func generate() -> MinimalGenerator> { expectUnreachable() return MinimalGenerator([]) } var startIndex: MinimalForwardIndex { return MinimalForwardIndex(position: 0, startIndex: 0, endIndex: _count) } var endIndex: MinimalForwardIndex { return MinimalForwardIndex( position: _count, startIndex: 0, endIndex: _count) } subscript(i: MinimalForwardIndex) -> OpaqueValue { expectUnreachable() return OpaqueValue(0xffff) } var _count: Int } SequenceTypeAlgorithms.test("underestimateCount/CollectionType/DefaultImplementation") { if true { let s = CollectionWithDefaultUnderestimateCount(count: 0) expectEqual(0, callGenericUnderestimatedCount(s)) } if true { let s = CollectionWithDefaultUnderestimateCount(count: 5) expectEqual(5, callGenericUnderestimatedCount(s)) } } struct CollectionWithCustomUnderestimateCount : CollectionType { init(underestimatedCount: Int) { self._underestimatedCount = underestimatedCount } func generate() -> MinimalGenerator> { expectUnreachable() return MinimalGenerator([]) } var startIndex: MinimalForwardIndex { expectUnreachable() return MinimalForwardIndex(position: 0, startIndex: 0, endIndex: 0xffff) } var endIndex: MinimalForwardIndex { expectUnreachable() return MinimalForwardIndex( position: 0xffff, startIndex: 0, endIndex: 0xffff) } subscript(i: MinimalForwardIndex) -> OpaqueValue { expectUnreachable() return OpaqueValue(0xffff) } func underestimateCount() -> Int { return _underestimatedCount } let _underestimatedCount: Int } SequenceTypeAlgorithms.test("underestimateCount/CollectionType/CustomImplementation") { if true { let s = CollectionWithCustomUnderestimateCount(underestimatedCount: 0) expectEqual(0, callGenericUnderestimatedCount(s)) } if true { let s = CollectionWithCustomUnderestimateCount(underestimatedCount: 5) expectEqual(5, callGenericUnderestimatedCount(s)) } } //===----------------------------------------------------------------------===// // _copyToNativeArrayBuffer() //===----------------------------------------------------------------------===// SequenceTypeAlgorithms.test("_copyToNativeArrayBuffer/OverestimatedCount") { let s = MinimalSequence>( [ 1, 2, 3 ]._prext_map { OpaqueValue($0) }, underestimatedCount: .Value(4)) expectCrashLater() let array = s~>_copyToNativeArrayBuffer() _blackHole(array) } //===----------------------------------------------------------------------===// // CollectionType.generate(), CollectionType.Generator //===----------------------------------------------------------------------===// struct MinimalForwardCollectionWithDefaultGenerator : CollectionType { init(count: Int) { self._count = count } var startIndex: MinimalForwardIndex { return MinimalForwardIndex(position: 0, startIndex: 0, endIndex: _count) } var endIndex: MinimalForwardIndex { return MinimalForwardIndex( position: _count, startIndex: 0, endIndex: _count) } subscript(i: MinimalForwardIndex) -> OpaqueValue { return OpaqueValue(i.position + 1) } var _count: Int } func callGenericGenerate(sequence: S) -> S.Generator { return sequence.generate() } SequenceTypeAlgorithms.test("CollectionType.generate()/DefaultImplementation") { for count in [ 0, 5 ] { let collection = MinimalForwardCollectionWithDefaultGenerator(count: count) if true { // Check the return type of the function when called statically. var generator = collection.generate() expectType( IndexingGenerator.self, &generator) } if true { // Check the return type of the function when called generically. var generator = callGenericGenerate(collection) expectType( IndexingGenerator.self, &generator) } checkForwardCollection( Array(1..], collection, { $0.value == $1.value }, SourceLocStack().withCurrentLoc()) } } struct MinimalForwardCollectionWithCustomGenerator : CollectionType { init(count: Int) { self._count = count } static var timesGenerateWasCalled: Int = 0 func generate() -> MinimalGenerator> { ++MinimalForwardCollectionWithCustomGenerator.timesGenerateWasCalled return MinimalGenerator>( Array(1..<_count+1)._prext_map { OpaqueValue($0) } as [OpaqueValue] ) } var startIndex: MinimalForwardIndex { return MinimalForwardIndex(position: 0, startIndex: 0, endIndex: _count) } var endIndex: MinimalForwardIndex { return MinimalForwardIndex( position: _count, startIndex: 0, endIndex: _count) } subscript(i: MinimalForwardIndex) -> OpaqueValue { return OpaqueValue(i.position + 1) } var _count: Int } SequenceTypeAlgorithms.test("CollectionType.generate()/CustomImplementation") { for count in [ 0, 5 ] { let collection = MinimalForwardCollectionWithCustomGenerator(count: count) if true { // Check the return type of the function when called statically. MinimalForwardCollectionWithCustomGenerator.timesGenerateWasCalled = 0 var generator = collection.generate() expectType( MinimalGenerator>.self, &generator) expectEqual(1, MinimalForwardCollectionWithCustomGenerator.timesGenerateWasCalled) } if true { MinimalForwardCollectionWithCustomGenerator.timesGenerateWasCalled = 0 // Check the return type of the function when called generically. var generator = callGenericGenerate(collection) expectType( MinimalGenerator>.self, &generator) expectEqual(1, MinimalForwardCollectionWithCustomGenerator.timesGenerateWasCalled) } checkForwardCollection( Array(1..], collection, { $0.value == $1.value }, resiliencyChecks: .none, SourceLocStack().withCurrentLoc()) } } //===----------------------------------------------------------------------===// // CollectionType.subscript(range:), CollectionType.SubSlice //===----------------------------------------------------------------------===// struct MinimalForwardCollectionWithDefaultSlicing : CollectionType { init(count: Int) { self._count = count } // FIXME: should return MinimalGenerator> func generate() -> MinimalGenerator> { return MinimalGenerator((1..<_count+1)._prext_map { OpaqueValue($0) }) } var startIndex: MinimalForwardIndex { return MinimalForwardIndex(position: 0, startIndex: 0, endIndex: _count) } var endIndex: MinimalForwardIndex { return MinimalForwardIndex( position: _count, startIndex: 0, endIndex: _count) } subscript(i: MinimalForwardIndex) -> OpaqueValue { return OpaqueValue(i.position + 1) } var _count: Int } func callGenericSlicing( collection: C, _ bounds: Range ) -> C._prext_SubSlice { return collection[bounds] } // FIXME: need separate tests for the Slice type itself. SequenceTypeAlgorithms.test("subscript(range:)/DefaultImplementation") { for count in [ 0, 5 ] { let collection = MinimalForwardCollectionWithDefaultSlicing(count: count) if true { // Check the return type of the function when called statically. var slice = collection[collection.startIndex...self, &slice) } if true { // Check the return type of the function when called generically. var slice = callGenericSlicing( collection, collection.startIndex...self, &slice) } // FIXME: improve checkForwardCollection to check the SubSlice type. checkForwardCollection( Array(1..], collection, { $0.value == $1.value }, resiliencyChecks: .none, SourceLocStack().withCurrentLoc()) } } struct MinimalForwardCollectionWithCustomSlicing : CollectionType { init(count: Int) { self._count = count } var startIndex: MinimalForwardIndex { return MinimalForwardIndex(position: 0, startIndex: 0, endIndex: _count) } var endIndex: MinimalForwardIndex { return MinimalForwardIndex( position: _count, startIndex: 0, endIndex: _count) } subscript(i: MinimalForwardIndex) -> OpaqueValue { return OpaqueValue(i.position + 1) } subscript(bounds: Range) -> CustomSlice { return CustomSlice( start: bounds.startIndex.position, end: bounds.endIndex.position) } var _count: Int } struct CustomSlice : CollectionType { init(start: Int, end: Int) { self._start = start self._end = end } var startIndex: MinimalForwardIndex { return MinimalForwardIndex( position: _start, startIndex: _start, endIndex: _end) } var endIndex: MinimalForwardIndex { return MinimalForwardIndex( position: _end, startIndex: _start, endIndex: _end) } subscript(i: MinimalForwardIndex) -> OpaqueValue { return OpaqueValue(i.position + 1) } var _start: Int var _end: Int } // FIXME: need separate tests for the Slice type itself. SequenceTypeAlgorithms.test("subscript(range:)/CustomImplementation") { for count in [ 0, 5 ] { let collection = MinimalForwardCollectionWithCustomSlicing(count: count) if true { // Check the return type of the function when called statically. var slice = collection[collection.startIndex..], collection, { $0.value == $1.value }, SourceLocStack().withCurrentLoc()) } } //===----------------------------------------------------------------------===// // isEmpty //===----------------------------------------------------------------------===// struct MinimalForwardCollectionWithDefaultIsEmpty : CollectionType { init(count: Int) { self._count = count } var startIndex: MinimalForwardIndex { return MinimalForwardIndex(position: 0, startIndex: 0, endIndex: _count) } var endIndex: MinimalForwardIndex { return MinimalForwardIndex( position: _count, startIndex: 0, endIndex: _count) } subscript(i: MinimalForwardIndex) -> OpaqueValue { expectUnreachable() return OpaqueValue(i.position + 1) } var _count: Int } func callStaticIsEmpty( collection: MinimalForwardCollectionWithDefaultIsEmpty ) -> Bool { return collection.isEmpty } func callGenericIsEmpty(collection: C) -> Bool { return collection.isEmpty } % for dispatch in [ 'Static', 'Generic' ]: SequenceTypeAlgorithms.test("isEmpty/DefaultImplementation/${dispatch}") { if true { let s = MinimalForwardCollectionWithDefaultIsEmpty(count: 0) expectTrue(call${dispatch}IsEmpty(s)) } if true { let s = MinimalForwardCollectionWithDefaultIsEmpty(count: 1) expectFalse(call${dispatch}IsEmpty(s)) } } % end struct MinimalForwardCollectionWithCustomIsEmpty : CollectionType { static var timesIsEmptyWasColled: Int = 0 init(count: Int) { self._count = count } var startIndex: MinimalForwardIndex { expectUnreachable() return MinimalForwardIndex(position: 0, startIndex: 0, endIndex: _count) } var endIndex: MinimalForwardIndex { expectUnreachable() return MinimalForwardIndex( position: _count, startIndex: 0, endIndex: _count) } subscript(i: MinimalForwardIndex) -> OpaqueValue { expectUnreachable() return OpaqueValue(i.position + 1) } var isEmpty: Bool { ++MinimalForwardCollectionWithCustomIsEmpty.timesIsEmptyWasColled return _count == 0 } var _count: Int } func callStaticIsEmpty( collection: MinimalForwardCollectionWithCustomIsEmpty ) -> Bool { return collection.isEmpty } % for dispatch in [ 'Static', 'Generic' ]: SequenceTypeAlgorithms.test("isEmpty/DefaultImplementation/${dispatch}") { if true { let s = MinimalForwardCollectionWithCustomIsEmpty(count: 0) MinimalForwardCollectionWithCustomIsEmpty.timesIsEmptyWasColled = 0 expectTrue(call${dispatch}IsEmpty(s)) expectEqual(1, MinimalForwardCollectionWithCustomIsEmpty.timesIsEmptyWasColled) } if true { let s = MinimalForwardCollectionWithCustomIsEmpty(count: 1) MinimalForwardCollectionWithCustomIsEmpty.timesIsEmptyWasColled = 0 expectFalse(call${dispatch}IsEmpty(s)) expectEqual(1, MinimalForwardCollectionWithCustomIsEmpty.timesIsEmptyWasColled) } } % end //===----------------------------------------------------------------------===// // first //===----------------------------------------------------------------------===// SequenceTypeAlgorithms.test("first") { if true { let s = MinimalForwardCollection>([]) expectEmpty(s.first) } if true { let s = MinimalForwardCollection>([ OpaqueValue(1, identity: 10), OpaqueValue(2, identity: 20) ]) if let result = s.first { expectEqual(1, result.value) expectEqual(10, result.identity) } else { expectUnreachable() } } } //===----------------------------------------------------------------------===// // last //===----------------------------------------------------------------------===// SequenceTypeAlgorithms.test("last") { if true { let s = MinimalBidirectionalCollection>([]) expectEmpty(s.last) } if true { let s = MinimalBidirectionalCollection>([ OpaqueValue(1, identity: 10), OpaqueValue(2, identity: 20) ]) if let result = s.last { expectEqual(2, result.value) expectEqual(20, result.identity) } else { expectUnreachable() } } } //===----------------------------------------------------------------------===// // count() //===----------------------------------------------------------------------===// % for Implementation in [ 'Default', 'Custom' ]: struct MinimalForwardCollectionWith${Implementation}Count : CollectionType { init(count: Int) { self._count = count } var startIndex: MinimalForwardInt32Index { return MinimalForwardInt32Index( position: 0, startIndex: 0, endIndex: _count) } var endIndex: MinimalForwardInt32Index { return MinimalForwardInt32Index( position: _count, startIndex: 0, endIndex: _count) } subscript(i: MinimalForwardInt32Index) -> OpaqueValue { return OpaqueValue(i.position + 1) } var _count: Int % if Implementation == 'Custom': static var timesCountWasCalled: Int = 0 func count() -> Int32 { ++MinimalForwardCollectionWithCustomCount.timesCountWasCalled return Int32(_count) } % end } % end func callGenericCount(collection: C) -> C.Index.Distance { return collection.count() } % for Implementation in [ 'Default', 'Custom' ]: SequenceTypeAlgorithms.test("CollectionType.count()/${Implementation}Implementation") { for count in [ 0, 5 ] { let collection = MinimalForwardCollectionWith${Implementation}Count(count: count) if true { // Check the return type of the function when called statically. % if Implementation == 'Custom': MinimalForwardCollectionWithCustomCount.timesCountWasCalled = 0 % end var result = collection.count() expectType(Int32.self, &result) expectEqual(Int32(count), result) % if Implementation == 'Custom': expectEqual(1, MinimalForwardCollectionWithCustomCount.timesCountWasCalled) % end } if true { // Check the return type of the function when called generically. % if Implementation == 'Custom': MinimalForwardCollectionWithCustomCount.timesCountWasCalled = 0 % end var result = callGenericCount(collection) expectType(Int32.self, &result) expectEqual(Int32(count), result) % if Implementation == 'Custom': expectEqual(1, MinimalForwardCollectionWithCustomCount.timesCountWasCalled) % end } checkForwardCollection( Array(1..], collection, { $0.value == $1.value }, SourceLocStack().withCurrentLoc()) } } % end //===----------------------------------------------------------------------===// // find() //===----------------------------------------------------------------------===// func callStaticFind( collection: MinimalForwardCollection, _ element: MinimalEquatableValue ) -> MinimalForwardCollection.Index? { return collection.indexOf(element) } func callGenericFind< C : CollectionType where C.Generator.Element : Equatable >(collection: C, _ element: C.Generator.Element) -> C.Index? { return collection.indexOf(element) } % for dispatch in [ 'Static', 'Generic' ]: SequenceTypeAlgorithms.test("find/WhereElementIsEquatable/${dispatch}") { for test in findTests { let s = MinimalForwardCollection( test.sequence.map { MinimalEquatableValue($0) }) expectEqual( test.expected, call${dispatch}Find(s, MinimalEquatableValue(test.element)) .map { $0.position }, stackTrace: test.loc.withCurrentLoc()) } } % end struct CollectionWithCustomFindMethod : CollectionType { static var timesFindWasCalled: Int = 0 internal let _elements: [Int] init(_ elements: [Int]) { self._elements = elements } func generate() -> MinimalGenerator { // Lie from our generate() method about sequence contents. // Tests using this type should not call generate() anyway. expectUnreachable() return MinimalSequence([]).generate() } var startIndex: MinimalForwardIndex { return MinimalForwardIndex( position: 0, startIndex: 0, endIndex: _elements.endIndex) } var endIndex: MinimalForwardIndex { return MinimalForwardIndex( position: _elements.endIndex, startIndex: 0, endIndex: _elements.endIndex) } subscript(i: MinimalForwardIndex) -> MinimalEquatableValue { return MinimalEquatableValue(_elements[i.position]) } func _customIndexOfEquatableElement( element: MinimalEquatableValue ) -> MinimalForwardIndex?? { ++CollectionWithCustomFindMethod.timesFindWasCalled for i in _elements.indices { if _elements[i] == element.value { return MinimalForwardIndex( position: i, startIndex: 0, endIndex: _elements.endIndex) } } return Optional(nil) } } func callStaticFind( sequence: CollectionWithCustomFindMethod, _ element: MinimalEquatableValue ) -> CollectionWithCustomFindMethod.Index? { return sequence.indexOf(element) } % for dispatch in [ 'Static', 'Generic' ]: SequenceTypeAlgorithms.test("find/WhereElementIsEquatable/CustomImplementation/${dispatch}") { for test in findTests { let s = CollectionWithCustomFindMethod(test.sequence) CollectionWithCustomFindMethod.timesFindWasCalled = 0 expectEqual( test.expected, call${dispatch}Find(s, MinimalEquatableValue(test.element)) .map { $0.position }, stackTrace: test.loc.withCurrentLoc()) expectEqual(1, CollectionWithCustomFindMethod.timesFindWasCalled) } } % end // FIXME: underscores are a workaround for: // Commenting out one line determines whether a // completely different line type-checks func callGenericFind_< C : CollectionType where C.Generator.Element : Equatable >(collection: C, _ element: C.Generator.Element) -> C.Index? { return collection.indexOf(element) } func callStaticFind_( set: Set, _ element: MinimalHashableValue ) -> Set.Index? { return set.indexOf(element) } % for dispatch in [ 'Static', 'Generic' ]: // FIXME: implement the same optimization for Dictionary. // FIXME: move to the file where other Set tests live. SequenceTypeAlgorithms.test("Set.find/WhereElementIsEquatable/CustomImplementation/${dispatch}") { for test in findTests { let s = Set( test.sequence.map { MinimalHashableValue($0) }) MinimalHashableValue.timesEqualEqualWasCalled = 0 MinimalHashableValue.timesHashValueWasCalled = 0 expectEqual( test.expected .map { _ in MinimalHashableValue(test.element) }, call${dispatch}Find_(s, MinimalHashableValue(test.element)) .map { s[$0] }, stackTrace: test.loc.withCurrentLoc()) if test.sequence.isEmpty { expectEqual( 0, MinimalHashableValue.timesEqualEqualWasCalled, stackTrace: test.loc.withCurrentLoc()) expectEqual( 0, MinimalHashableValue.timesHashValueWasCalled, stackTrace: test.loc.withCurrentLoc()) } else { expectNotEqual( 0, MinimalHashableValue.timesHashValueWasCalled, stackTrace: test.loc.withCurrentLoc()) } if test.expected != nil { expectNotEqual( 0, MinimalHashableValue.timesEqualEqualWasCalled, stackTrace: test.loc.withCurrentLoc()) } } } % end SequenceTypeAlgorithms.test("find/Predicate") { expectEqual(0, LifetimeTracked.instances) for test in findTests { let s = MinimalForwardCollection( test.sequence.map { MinimalEquatableValue($0) }) let closureLifetimeTracker = LifetimeTracked(0) expectEqual(1, LifetimeTracked.instances) let result = s.indexOf { (candidate) in _blackHole(closureLifetimeTracker) return candidate.value == test.element } expectEqual( test.expected, result.map { $0.position }, stackTrace: test.loc.withCurrentLoc()) } expectEqual(0, LifetimeTracked.instances) } //===----------------------------------------------------------------------===// // indices //===----------------------------------------------------------------------===// SequenceTypeAlgorithms.test("indices") { if true { let s = MinimalForwardCollection>([]) let indices = s.indices expectEqual(s.startIndex, indices.startIndex) expectEqual(s.endIndex, indices.endIndex) } if true { let s = MinimalForwardCollection>([ OpaqueValue(1, identity: 10), OpaqueValue(2, identity: 20) ]) let indices = s.indices expectEqual(s.startIndex, indices.startIndex) expectEqual(s.endIndex, indices.endIndex) } } //===----------------------------------------------------------------------===// // partition() //===----------------------------------------------------------------------===// func _forAllPermutationsImpl( index: Int, _ size: Int, inout _ perm: [Int], inout _ visited: [Bool], _ body: ([Int]) -> () ) { if index == size { body(perm) return } for i in 0.. ()) { if size == 0 { return } var permutation = [Int](count: size, repeatedValue: 0) var visited = [Bool](count: size, repeatedValue: false) _forAllPermutationsImpl(0, size, &permutation, &visited, body) } /// Generate all permutations. func forAllPermutations( sequence: S, body: ([S.Generator.Element]) -> () ) { let data = Array(sequence) forAllPermutations(data.count) { (indices: [Int]) in body(indices._prext_map { data[$0] }) return () } } SequenceTypeAlgorithms.test("forAllPermutations") { if true { var permutations: [[Int]] = [] forAllPermutations(0) { permutations.append($0) } expectEqualSequence([] as [[Int]], permutations, { $0 == $1 }) } if true { var permutations: [[Int]] = [] forAllPermutations(1) { permutations.append($0) } expectEqualSequence([ [ 0 ] ] as [[Int]], permutations, { $0 == $1 }) } if true { var permutations: [[Int]] = [] forAllPermutations(2) { permutations.append($0) } expectEqualSequence( [ [ 0, 1 ], [ 1, 0 ] ] as [[Int]], permutations, { $0 == $1 }) } if true { var permutations: [[Int]] = [] forAllPermutations(3) { permutations.append($0) } expectEqualSequence( [ [ 0, 1, 2 ], [ 0, 2, 1 ], [ 1, 0, 2 ], [ 1, 2, 0 ], [ 2, 0, 1 ], [ 2, 1, 0 ], ] as [[Int]], permutations, { $0 == $1 }) } if true { var permutations: [[Int]] = [] forAllPermutations([ 10, 20, 30 ]) { permutations.append($0) } expectEqualSequence( [ [ 10, 20, 30 ], [ 10, 30, 20 ], [ 20, 10, 30 ], [ 20, 30, 10 ], [ 30, 10, 20 ], [ 30, 20, 10 ], ] as [[Int]], permutations, { $0 == $1 }) } } public struct CustomComparableValue : Equatable, Comparable { public static var timesEqualEqualWasCalled: Int = 0 public static var timesLessWasCalled: Int = 0 public static var equalImpl: (Int, Int) -> Bool = { $0 == $1 } public static var lessImpl: (Int, Int) -> Bool = { $0 < $1 } public var value: Int public var identity: Int public init(_ value: Int) { self.value = value self.identity = 0 } public init(_ value: Int, identity: Int) { self.value = value self.identity = identity } } public func == ( lhs: CustomComparableValue, rhs: CustomComparableValue ) -> Bool { ++CustomComparableValue.timesEqualEqualWasCalled return CustomComparableValue.equalImpl(lhs.value, rhs.value) } public func < ( lhs: CustomComparableValue, rhs: CustomComparableValue ) -> Bool { ++CustomComparableValue.timesLessWasCalled return CustomComparableValue.lessImpl(lhs.value, rhs.value) } struct PartitionExhaustiveTest { let sequence: [Int] let loc: SourceLoc init( _ sequence: [Int], file: String = __FILE__, line: UWord = __LINE__ ) { self.sequence = sequence self.loc = SourceLoc(file, line, comment: "test data") } } let partitionExhaustiveTests = [ PartitionExhaustiveTest([]), PartitionExhaustiveTest([ 10 ]), PartitionExhaustiveTest([ 10, 10 ]), PartitionExhaustiveTest([ 10, 20 ]), PartitionExhaustiveTest([ 10, 10, 10 ]), PartitionExhaustiveTest([ 10, 10, 20 ]), PartitionExhaustiveTest([ 10, 20, 20 ]), PartitionExhaustiveTest([ 10, 20, 30 ]), PartitionExhaustiveTest([ 10, 10, 10, 10 ]), PartitionExhaustiveTest([ 10, 10, 10, 20 ]), PartitionExhaustiveTest([ 10, 10, 20, 20 ]), PartitionExhaustiveTest([ 10, 20, 30, 40 ]), PartitionExhaustiveTest([ 10, 10, 10, 10, 10 ]), PartitionExhaustiveTest([ 10, 10, 10, 20, 20 ]), PartitionExhaustiveTest([ 10, 10, 10, 20, 30 ]), PartitionExhaustiveTest([ 10, 10, 20, 20, 30 ]), PartitionExhaustiveTest([ 10, 10, 20, 30, 40 ]), PartitionExhaustiveTest([ 10, 20, 30, 40, 50 ]), PartitionExhaustiveTest([ 10, 20, 30, 40, 50, 60 ]), PartitionExhaustiveTest([ 10, 10, 10, 10, 10, 20, 20 ]), PartitionExhaustiveTest([ 10, 20, 30, 40, 50, 60, 70 ]), ] % for predicate in [ False, True ]: SequenceTypeAlgorithms.test("partition/${'Predicate' if predicate else 'WhereElementIsEquatable'}") { % if not predicate: CustomComparableValue.equalImpl = { $0 == $1 } CustomComparableValue.lessImpl = { $0 < $1 } % end expectEqual(0, LifetimeTracked.instances) for test in partitionExhaustiveTests { forAllPermutations(test.sequence) { (sequence) in % for slice in [ False, True ]: if true { % if predicate: var sequenceAsArray: [OpaqueValue] = zip(sequence, 0..>( sequenceAsArray) % if slice: let indices = s.startIndex.successor()..( sequenceAsArray) % if slice: let indices = s.startIndex.successor()..>( sequence._prext_map { OpaqueValue($0) }) let closureLifetimeTracker = LifetimeTracked(0) expectEqual(1, LifetimeTracked.instances) let pivot = s._prext_partition(s.indices) { (lhs, rhs) in _blackHole(closureLifetimeTracker) return comparisonPredicate(lhs.value, rhs.value) } % else: var s = MinimalMutableRandomAccessCollection( sequence._prext_map { CustomComparableValue($0) }) CustomComparableValue.equalImpl = { !comparisonPredicate($0, $1) && !comparisonPredicate($1, $0) } CustomComparableValue.lessImpl = { comparisonPredicate($0, $1) } let pivot = s._prext_partition(s.indices) % end // Weak postcondition: we didn't lose any values. expectEqualsUnordered(0..