Files
swift-mirror/test/1_stdlib/Algorithm.swift.gyb
Dmitri Hrybenko 61214ec55b stdlib: remove Sliceable conformance from String
Swift SVN r28442
2015-05-11 20:58:31 +00:00

3309 lines
98 KiB
Swift

// -*- 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<Int>([], 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<Int>([])
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<Int>([], 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<Int>([])
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<T> that disables any type-specific algorithm
// optimizations and forces bounds checking on.
struct A<T> : MutableSliceable {
init(_ a: Array<T>) {
impl = a
}
var startIndex: Int {
return 0
}
var endIndex: Int {
return impl.count
}
func generate() -> Array<T>.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<Int>) -> Array<T>.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<T>
}
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<Int> {
let count = Int(rand32(exclusiveUpperBound: 50))
return A(randArray(count))
}
Algorithm.test("invalidOrderings") {
withInvalidOrderings {
var a = randomArray()
sort(&a, $0)
}
withInvalidOrderings {
var a: A<Int>
a = randomArray()
partition(&a, a.indices, $0)
}
/*
// FIXME: Disabled due to <rdar://problem/17734737> 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..<len { ary[i] = i }
ary = sorted(ary, Compare)
for i in 0..<len {
ret[ary[i]] = i
}
return ret
}
Algorithm.test("sorted/complexity") {
var ary: [Int] = []
// Check performance of sort on array of repeating values
var comparisons_100 = 0
ary = [Int](count: 100, repeatedValue: 0)
sort(&ary) { comparisons_100++; return $0 < $1 }
var comparisons_1000 = 0
ary = [Int](count: 1000, repeatedValue: 0)
sort(&ary) { comparisons_1000++; return $0 < $1 }
expectTrue(comparisons_1000/comparisons_100 < 20)
// Try to construct 'bad' case for quicksort, on which the algorithm
// goes quadratic.
comparisons_100 = 0
ary = makeQSortKiller(100)
sort(&ary) { comparisons_100++; return $0 < $1 }
comparisons_1000 = 0
ary = makeQSortKiller(1000)
sort(&ary) { comparisons_1000++; return $0 < $1 }
expectTrue(comparisons_1000/comparisons_100 < 20)
}
Algorithm.test("sorted/return type") {
let x: Array = sorted([5, 4, 3, 2, 1] as ArraySlice)
}
var SequenceTypeAlgorithms = TestSuite("SequenceTypeAlgorithms")
// FIXME: add tests for:
//
// - Array, ContiguousArray and ArraySlice as inputs. These types special-case
// a lot of collection behavior for performance reasons. Not to even mention
// that these are important types to test in any case.
//
// - NaN behavior of floating point types, combined with these generic
// algorithms, should make sense if possible. For example,
// [1.0, Double.NaN].startsWith([1.0, 2.0]) should be false.
//===----------------------------------------------------------------------===//
// enumerate()
//===----------------------------------------------------------------------===//
struct EnumerateTest {
let expected: [(Int, Int)]
let sequence: [Int]
let loc: SourceLoc
init(
_ expected: [(Int, Int)], _ sequence: [Int],
file: String = __FILE__, line: UWord = __LINE__,
comment: String = ""
) {
self.expected = expected
self.sequence = sequence
self.loc = SourceLoc(file, line, comment: "test data" + comment)
}
}
let enumerateTests = [
EnumerateTest([], []),
EnumerateTest([ (0, 10) ], [ 10 ]),
EnumerateTest([ (0, 10), (1, 20) ], [ 10, 20 ]),
EnumerateTest([ (0, 10), (1, 20), (2, 30) ], [ 10, 20, 30 ]),
]
SequenceTypeAlgorithms.test("enumerate") {
typealias Element = (index: Int, element: OpaqueValue<Int>)
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<OpaqueValue<Int>>(
test.sequence._prext_map { OpaqueValue($0) })
var result = s.enumerate()
expectType(
EnumerateSequence<MinimalSequence<OpaqueValue<Int>>>.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<MinimalComparableValue>(
test.sequence.enumerate()._prext_map {
MinimalComparableValue($1, identity: $0)
})
var maybeResult = s.${algorithmKind}Element()
expectType(Optional<MinimalComparableValue>.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<OpaqueValue<Int>>(
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<OpaqueValue<Int>>.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<MinimalEquatableValue>(
test.sequence.map { MinimalEquatableValue($0) })
let prefix = MinimalSequence<MinimalEquatableValue>(
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<MinimalEquatableValue>(
test.sequence.map { MinimalEquatableValue($0) })
let prefix = MinimalSequence<MinimalEquatableValue>(
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<OpaqueValue<Int>>(
map(test.sequence) { OpaqueValue($0) })
let prefix = MinimalSequence<OpaqueValue<Int>>(
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<OpaqueValue<Int>>(
map(test.sequence) { OpaqueValue($0 * 2) })
let prefix = MinimalSequence<OpaqueValue<Int>>(
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<OpaqueValue<Int>>(
map(test.sequence) { OpaqueValue($0) })
let prefix = MinimalSequence<OpaqueValue<Int>>(
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<MinimalEquatableValue>(
test.sequence.map { MinimalEquatableValue($0) })
let other = MinimalSequence<MinimalEquatableValue>(
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<MinimalEquatableValue>(
test.sequence.map { MinimalEquatableValue($0) })
let other = MinimalSequence<MinimalEquatableValue>(
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<OpaqueValue<Int>>(
test.sequence.map { OpaqueValue($0) })
let other = MinimalSequence<OpaqueValue<Int>>(
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<OpaqueValue<Int>>(
test.sequence.map { OpaqueValue($0) })
let other = MinimalSequence<OpaqueValue<Int>>(
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<MinimalComparableValue>(
test.sequence.map { MinimalComparableValue($0) })
let other = MinimalSequence<MinimalComparableValue>(
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<MinimalComparableValue>(
test.sequence.map { MinimalComparableValue($0) })
let other = MinimalSequence<MinimalComparableValue>(
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<OpaqueValue<Int>>(
test.sequence.map { OpaqueValue($0) })
let other = MinimalSequence<OpaqueValue<Int>>(
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<OpaqueValue<Int>>(
test.sequence.map { OpaqueValue($0) })
let other = MinimalSequence<OpaqueValue<Int>>(
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<MinimalEquatableValue>,
_ 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<MinimalEquatableValue>(
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<MinimalEquatableValue> {
// Lie from our generate() method about sequence contents.
// Tests using this type should not call generate() anyway.
expectUnreachable()
return MinimalSequence<MinimalEquatableValue>([]).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<MinimalHashableValue>,
_ 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<T>.contains/WhereElementIsEquatable/CustomImplementation/${dispatch}") {
for test in findTests {
let s = Set<MinimalHashableValue>(
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<OpaqueValue<Int>>(
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<OpaqueValue<Int>>(
test.sequence.map { OpaqueValue($0) })
var timesClosureWasCalled = 0
let result = s.reduce(OpaqueValue<[Int]>([])) {
(partialResult: OpaqueValue<[Int]>, element: OpaqueValue<Int>)
-> 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<OpaqueValue<Int>>(
test.sequence.map { OpaqueValue($0) })
var result = s.reverse()
expectType([OpaqueValue<Int>].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<OpaqueValue<Int>>(
test.sequence.map { OpaqueValue($0) })
var result = s.reverse()
expectType(
BidirectionalReverseView<MinimalBidirectionalCollection<OpaqueValue<Int>>>.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<Int>],
result,
{ $0.value == $1.value },
test.loc.withCurrentLoc())
}
}
SequenceTypeAlgorithms.test("reverse/WhereIndexIsRandomAccess,RandomAccessReverseView") {
for test in reverseTests {
let s = MinimalRandomAccessCollection<OpaqueValue<Int>>(
test.sequence.map { OpaqueValue($0) })
var result = s.reverse()
expectType(
RandomAccessReverseView<MinimalRandomAccessCollection<OpaqueValue<Int>>>.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<Int>],
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<OpaqueValue<Int>>,
@noescape includeElement: (OpaqueValue<Int>) -> Bool
) -> [OpaqueValue<Int>] {
var result = sequence._prext_filter(includeElement)
expectType([OpaqueValue<Int>].self, &result)
return result
}
func callGenericSequenceFilter<S : SequenceType>(
sequence: S,
@noescape includeElement: (S.Generator.Element) -> Bool
) -> [S.Generator.Element] {
var result = sequence._prext_filter(includeElement)
expectType(Array<S.Generator.Element>.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<OpaqueValue<Int>>(
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<Int>].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<C : RangeReplaceableCollectionType>(
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<Int>]
var reservedCapacity: Int = 0
init() {
self.elements = []
}
init(_ elements: [OpaqueValue<Int>]) {
self.elements = elements
}
func generate() -> MinimalGenerator<OpaqueValue<Int>> {
return MinimalSequence<OpaqueValue<Int>>(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<Int> {
return elements[i.position]
}
mutating func reserveCapacity(n: Int) {
elements.reserveCapacity(n)
reservedCapacity = max(reservedCapacity, n)
}
mutating func append(x: OpaqueValue<Int>) {
elements.append(x)
}
mutating func extend<
S : SequenceType where S.Generator.Element == OpaqueValue<Int>
>(newElements: S) {
expectUnreachable()
}
mutating func replaceRange<
C : CollectionType where C.Generator.Element == OpaqueValue<Int>
>(
subRange: Range<MinimalForwardIndex>, with newElements: C
) {
expectUnreachable()
}
mutating func insert(
newElement: OpaqueValue<Int>, atIndex i: MinimalForwardIndex
) {
expectUnreachable()
}
mutating func splice<
S : CollectionType where S.Generator.Element == OpaqueValue<Int>
>(newElements: S, atIndex i: MinimalForwardIndex) {
expectUnreachable()
}
mutating func removeAtIndex(i: MinimalForwardIndex) -> OpaqueValue<Int> {
expectUnreachable()
return OpaqueValue(0xffff)
}
mutating func removeRange(subRange: Range<MinimalForwardIndex>) {
expectUnreachable()
}
mutating func removeAll(#keepCapacity: Bool = false) {
expectUnreachable()
}
% if Implementation == 'Custom':
func _prext_filter(
@noescape includeElement: (OpaqueValue<Int>) -> Bool
) -> ${CollectionType} {
++RangeReplaceableCollectionWithCustomFilterMethod.timesFilterWasCalled
return ${CollectionType}(elements._prext_filter(includeElement))
}
% end
}
% end
% for (CollectionType, CollectionKind) in [
% ('MinimalForwardRangeReplaceableCollectionType<OpaqueValue<Int>>', 'Minimal'),
% ('RangeReplaceableCollectionWithDefaultFilterMethod', 'DefaultImplementation'),
% ('RangeReplaceableCollectionWithCustomFilterMethod', 'CustomImplementation'),
% ('Array<OpaqueValue<Int>>', 'StdlibArray'),
% ('ContiguousArray<OpaqueValue<Int>>', 'StdlibArray'),
% ('ArraySlice<OpaqueValue<Int>>', 'StdlibArray')
% ]:
% for dispatch in [ 'Static', 'Generic' ]:
% if dispatch == 'Static':
func callStaticCollectionFilter(
collection: ${CollectionType},
@noescape includeElement: (OpaqueValue<Int>) -> 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<Element> : SequenceType {
init(_ data: [Element], underestimatedCount: UnderestimateCountBehavior) {
self._data = MinimalSequence(
data, underestimatedCount: underestimatedCount)
}
func generate() -> MinimalGenerator<Element> {
return _data.generate()
}
var _data: MinimalSequence<Element>
% if Implementation == 'Custom':
static var timesMapWasCalled: Int {
get {
return MinimalSequenceWithCustomMap_timesMapWasCalled
}
set {
MinimalSequenceWithCustomMap_timesMapWasCalled = newValue
}
}
func _prext_map<T>(
@noescape transform: (Element) -> T
) -> [T] {
++MinimalSequenceWithCustomMap.timesMapWasCalled
return _data._prext_map(transform)
}
% end
}
% end
func callStaticSequenceMap<T>(
sequence: MinimalSequenceWithDefaultMap<OpaqueValue<Int>>,
@noescape transform: (OpaqueValue<Int>) -> T
) -> [T] {
var result = sequence._prext_map(transform)
expectType([T].self, &result)
return result
}
func callStaticSequenceMap<T>(
sequence: MinimalSequenceWithCustomMap<OpaqueValue<Int>>,
@noescape transform: (OpaqueValue<Int>) -> T
) -> [T] {
var result = sequence._prext_map(transform)
expectType([T].self, &result)
return result
}
func callGenericSequenceMap<S : SequenceType, T>(
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<OpaqueValue<Int>>(
test.sequence._prext_map { OpaqueValue($0) },
underestimatedCount: underestimateCountBehavior)
let closureLifetimeTracker = LifetimeTracked(0)
expectEqual(1, LifetimeTracked.instances)
var timesClosureWasCalled = 0
% if Implementation == 'Custom':
MinimalSequenceWithCustomMap<OpaqueValue<Int>>.timesMapWasCalled = 0
% end
var result = call${dispatch}SequenceMap(s) {
(element: OpaqueValue<Int>) -> OpaqueValue<Int32> in
_blackHole(closureLifetimeTracker)
++timesClosureWasCalled
return OpaqueValue(Int32(test.transform(element.value)))
}
expectType([OpaqueValue<Int32>].self, &result)
expectEqual(test.expected, result._prext_map { $0.value })
% if Implementation == 'Custom':
expectEqual(1, MinimalSequenceWithCustomMap<OpaqueValue<Int>>.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<Element>
: CollectionType {
init(_ data: [Element], underestimatedCount: UnderestimateCountBehavior) {
self._data = MinimalForwardCollection(
data, underestimatedCount: underestimatedCount)
}
func generate() -> MinimalGenerator<Element> {
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<Element>
% if Implementation == 'Custom':
static var timesMapWasCalled: Int {
get {
return MinimalForwardCollectionWithCustomMap_timesMapWasCalled
}
set {
MinimalForwardCollectionWithCustomMap_timesMapWasCalled = newValue
}
}
func _prext_map<T>(
@noescape transform: (Element) -> T
) -> [T] {
++MinimalForwardCollectionWithCustomMap.timesMapWasCalled
return _data._prext_map(transform)
}
% end
}
% end
func callStaticCollectionMap<T>(
collection: MinimalForwardCollectionWithDefaultMap<OpaqueValue<Int>>,
@noescape transform: (OpaqueValue<Int>) -> T
) -> [T] {
var result = collection._prext_map(transform)
expectType([T].self, &result)
return result
}
func callStaticCollectionMap<T>(
collection: MinimalForwardCollectionWithCustomMap<OpaqueValue<Int>>,
@noescape transform: (OpaqueValue<Int>) -> T
) -> [T] {
var result = collection._prext_map(transform)
expectType([T].self, &result)
return result
}
func callGenericCollectionMap<C : CollectionType, T>(
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<OpaqueValue<Int>>(
test.sequence.map { OpaqueValue($0) },
underestimatedCount: underestimateCountBehavior)
let closureLifetimeTracker = LifetimeTracked(0)
expectEqual(1, LifetimeTracked.instances)
var timesClosureWasCalled = 0
% if Implementation == 'Custom':
MinimalForwardCollectionWithCustomMap<OpaqueValue<Int>>.timesMapWasCalled = 0
% end
var result = call${dispatch}CollectionMap(s) {
(element: OpaqueValue<Int>) -> OpaqueValue<Int32> in
_blackHole(closureLifetimeTracker)
++timesClosureWasCalled
return OpaqueValue(Int32(test.transform(element.value)))
}
expectType([OpaqueValue<Int32>].self, &result)
expectEqual(test.expected, result._prext_map { $0.value })
% if Implementation == 'Custom':
expectEqual(1, MinimalForwardCollectionWithCustomMap<OpaqueValue<Int>>.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<OpaqueValue<Int>>(
test.sequence.map { OpaqueValue($0) },
underestimatedCount: underestimateCountBehavior)
let closureLifetimeTracker = LifetimeTracked(0)
expectEqual(1, LifetimeTracked.instances)
var timesClosureWasCalled = 0
var result = s.flatMap {
(element: OpaqueValue<Int>) -> MinimalSequence<OpaqueValue<Int32>> in
_blackHole(closureLifetimeTracker)
++timesClosureWasCalled
return MinimalSequence<OpaqueValue<Int32>>(
test.transform(element.value).map { OpaqueValue(Int32($0)) })
}
expectType([OpaqueValue<Int32>].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<OpaqueValue<Int>>(
test.sequence.map { OpaqueValue($0) },
underestimatedCount: underestimateCountBehavior)
let closureLifetimeTracker = LifetimeTracked(0)
expectEqual(1, LifetimeTracked.instances)
var timesClosureWasCalled = 0
var result = s.flatMap {
(element: OpaqueValue<Int>) -> OpaqueValue<Int32>? in
_blackHole(closureLifetimeTracker)
++timesClosureWasCalled
return test.transform(element.value).map { OpaqueValue(Int32($0)) }
}
expectType([OpaqueValue<Int32>].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<Int>, OpaqueValue<Int32>)
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<OpaqueValue<Int>>(
test.sequence.map { OpaqueValue($0) })
let other = MinimalSequence<OpaqueValue<Int32>>(
test.other.map { OpaqueValue($0) })
var result = zip(s, other)
expectType(
Zip2<MinimalSequence<OpaqueValue<Int>>, MinimalSequence<OpaqueValue<Int32>>>.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 : SequenceType>(s: S) -> Int {
return s.underestimateCount()
}
struct SequenceWithDefaultUnderestimateCount : SequenceType {
init() {}
func generate() -> MinimalSequence<OpaqueValue<Int>>.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<OpaqueValue<Int>>.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<OpaqueValue<Int>> {
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<Int> {
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<OpaqueValue<Int>> {
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<Int> {
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<OpaqueValue<Int>>(
[ 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<Int> {
return OpaqueValue(i.position + 1)
}
var _count: Int
}
func callGenericGenerate<S : SequenceType>(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<MinimalForwardCollectionWithDefaultGenerator>.self,
&generator)
}
if true {
// Check the return type of the function when called generically.
var generator = callGenericGenerate(collection)
expectType(
IndexingGenerator<MinimalForwardCollectionWithDefaultGenerator>.self,
&generator)
}
checkForwardCollection(
Array(1..<count+1)._prext_map { OpaqueValue($0) } as [OpaqueValue<Int>],
collection,
{ $0.value == $1.value },
SourceLocStack().withCurrentLoc())
}
}
struct MinimalForwardCollectionWithCustomGenerator : CollectionType {
init(count: Int) {
self._count = count
}
static var timesGenerateWasCalled: Int = 0
func generate() -> MinimalGenerator<OpaqueValue<Int>> {
++MinimalForwardCollectionWithCustomGenerator.timesGenerateWasCalled
return MinimalGenerator<OpaqueValue<Int>>(
Array(1..<_count+1)._prext_map { OpaqueValue($0) } as [OpaqueValue<Int>]
)
}
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<Int> {
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<OpaqueValue<Int>>.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<OpaqueValue<Int>>.self,
&generator)
expectEqual(1, MinimalForwardCollectionWithCustomGenerator.timesGenerateWasCalled)
}
checkForwardCollection(
Array(1..<count+1)._prext_map { OpaqueValue($0) } as [OpaqueValue<Int>],
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<OpaqueValue<Int>>
func generate() -> MinimalGenerator<OpaqueValue<Int>> {
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<Int> {
return OpaqueValue(i.position + 1)
}
var _count: Int
}
func callGenericSlicing<C : CollectionType>(
collection: C,
_ bounds: Range<C.Index>
) -> 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..<collection.endIndex]
expectType(
_prext_Slice<MinimalForwardCollectionWithDefaultSlicing>.self,
&slice)
}
if true {
// Check the return type of the function when called generically.
var slice = callGenericSlicing(
collection,
collection.startIndex..<collection.endIndex)
expectType(
_prext_Slice<MinimalForwardCollectionWithDefaultSlicing>.self,
&slice)
}
// FIXME: improve checkForwardCollection to check the SubSlice type.
checkForwardCollection(
Array(1..<count+1)._prext_map { OpaqueValue($0) } as [OpaqueValue<Int>],
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<Int> {
return OpaqueValue(i.position + 1)
}
subscript(bounds: Range<MinimalForwardIndex>) -> 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<Int> {
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.endIndex]
expectType(CustomSlice.self, &slice)
}
if true {
// Check the return type of the function when called generically.
var slice = callGenericSlicing(
collection,
collection.startIndex..<collection.endIndex)
expectType(CustomSlice.self, &slice)
}
// FIXME: improve checkForwardCollection to check the SubSlice type.
checkForwardCollection(
Array(1..<count+1)._prext_map { OpaqueValue($0) } as [OpaqueValue<Int>],
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<Int> {
expectUnreachable()
return OpaqueValue(i.position + 1)
}
var _count: Int
}
func callStaticIsEmpty(
collection: MinimalForwardCollectionWithDefaultIsEmpty
) -> Bool {
return collection.isEmpty
}
func callGenericIsEmpty<C : CollectionType>(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<Int> {
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<OpaqueValue<Int>>([])
expectEmpty(s.first)
}
if true {
let s = MinimalForwardCollection<OpaqueValue<Int>>([
OpaqueValue<Int>(1, identity: 10),
OpaqueValue<Int>(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<OpaqueValue<Int>>([])
expectEmpty(s.last)
}
if true {
let s = MinimalBidirectionalCollection<OpaqueValue<Int>>([
OpaqueValue<Int>(1, identity: 10),
OpaqueValue<Int>(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<Int> {
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<C : CollectionType>(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..<count+1)._prext_map { OpaqueValue($0) } as [OpaqueValue<Int>],
collection,
{ $0.value == $1.value },
SourceLocStack().withCurrentLoc())
}
}
% end
//===----------------------------------------------------------------------===//
// find()
//===----------------------------------------------------------------------===//
func callStaticFind(
collection: MinimalForwardCollection<MinimalEquatableValue>,
_ element: MinimalEquatableValue
) -> MinimalForwardCollection<MinimalEquatableValue>.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<MinimalEquatableValue>(
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<MinimalEquatableValue> {
// Lie from our generate() method about sequence contents.
// Tests using this type should not call generate() anyway.
expectUnreachable()
return MinimalSequence<MinimalEquatableValue>([]).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:
// <rdar://problem/20582358> 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<MinimalHashableValue>,
_ element: MinimalHashableValue
) -> Set<MinimalHashableValue>.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<T>.find/WhereElementIsEquatable/CustomImplementation/${dispatch}") {
for test in findTests {
let s = Set<MinimalHashableValue>(
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<MinimalEquatableValue>(
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<OpaqueValue<Int>>([])
let indices = s.indices
expectEqual(s.startIndex, indices.startIndex)
expectEqual(s.endIndex, indices.endIndex)
}
if true {
let s = MinimalForwardCollection<OpaqueValue<Int>>([
OpaqueValue<Int>(1, identity: 10),
OpaqueValue<Int>(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..<size {
if visited[i] {
continue
}
visited[i] = true
perm[index] = i
_forAllPermutationsImpl(index + 1, size, &perm, &visited, body)
visited[i] = false
}
}
/// Generate all permutations.
func forAllPermutations(size: Int, body: ([Int]) -> ()) {
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<S : SequenceType>(
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<Int>] =
zip(sequence, 0..<sequence.count)._prext_map {
OpaqueValue($0, identity: $1)
}
% if slice:
sequenceAsArray.insert(
OpaqueValue(0xfffe, identity: 0xfffe), atIndex: 0)
sequenceAsArray.append(OpaqueValue(0xffff, identity: 0xffff))
% end
var s = MinimalMutableRandomAccessCollection<OpaqueValue<Int>>(
sequenceAsArray)
% if slice:
let indices = s.startIndex.successor()..<s.endIndex.predecessor()
% else:
let indices = s.indices
% end
let closureLifetimeTracker = LifetimeTracked(0)
expectEqual(1, LifetimeTracked.instances)
let pivot = s._prext_partition(indices) {
(lhs, rhs) in
_blackHole(closureLifetimeTracker)
return lhs.value < rhs.value
}
% else:
var sequenceAsArray: [CustomComparableValue] =
zip(sequence, 0..<sequence.count)._prext_map {
CustomComparableValue($0, identity: $1)
}
% if slice:
sequenceAsArray.insert(
CustomComparableValue(0xfffe, identity: 0xfffe), atIndex: 0)
sequenceAsArray.append(CustomComparableValue(0xffff, identity: 0xffff))
% end
var s = MinimalMutableRandomAccessCollection<CustomComparableValue>(
sequenceAsArray)
% if slice:
let indices = s.startIndex.successor()..<s.endIndex.predecessor()
% else:
let indices = s.indices
% end
let pivot = s._prext_partition(indices)
% end
// Check that we didn't lose any values.
% if slice:
expectEqual(0xfffe, s.first!.identity)
expectEqual(0xffff, s.last!.identity)
var identities = s._prext_map { $0.identity }
identities.removeLast()
identities.removeAtIndex(0)
expectEqualsUnordered(0..<sequence.count, identities)
% else:
expectEqualsUnordered(0..<sequence.count, s._prext_map { $0.identity })
% end
// All the elements in the first partition are less than the pivot
// value.
for i in indices.startIndex..<pivot {
expectLT(s[i].value, s[pivot].value)
}
// All the elements in the second partition are greater or equal to
// the pivot value.
for i in pivot..<indices.endIndex {
expectLE(s[pivot].value, s[i].value)
}
}
% end
}
}
expectEqual(0, LifetimeTracked.instances)
}
% end
% for predicate in [ False, True ]:
SequenceTypeAlgorithms.test("partition/${'Predicate' if predicate else 'WhereElementIsEquatable'}/InvalidOrderings") {
expectEqual(0, LifetimeTracked.instances)
withInvalidOrderings { (comparisonPredicate) in
for i in 0..<7 {
forAllPermutations(i) { (sequence) in
% if predicate:
var s = MinimalMutableRandomAccessCollection<OpaqueValue<Int>>(
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<CustomComparableValue>(
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..<i, s._prext_map { $0.value })
expectTrue(0 <= s[pivot].value && s[pivot].value < i)
}
}
}
expectEqual(0, LifetimeTracked.instances)
}
% end
runAllTests()