| // -*- swift -*- |
| // RUN: %target-run-simple-swiftgyb |
| // REQUIRES: executable_test |
| |
| // <rdar://problem/24357067> The compiler never finishes compiling validation-test/stdlib/CollectionType.swift.gyb in -O |
| // REQUIRES: swift_test_mode_optimize_none |
| |
| % import os.path |
| % import gyb |
| % from gyb_stdlib_support import TRAVERSALS, collectionForTraversal, sliceTypeName, defaultIndicesForTraversal |
| |
| import StdlibUnittest |
| import StdlibCollectionUnittest |
| |
| |
| var CollectionTypeTests = TestSuite("Collection") |
| |
| struct CollectionWithDefaultUnderestimatedCount : Collection { |
| init(count: Int) { |
| self._count = count |
| self._collectionState = |
| _CollectionState(newRootStateForElementCount: count) |
| } |
| |
| func makeIterator() -> MinimalIterator<OpaqueValue<Int>> { |
| expectUnreachable() |
| return MinimalIterator([]) |
| } |
| |
| var startIndex: MinimalIndex { |
| return MinimalIndex( |
| collectionState: _collectionState, |
| position: 0, startIndex: 0, endIndex: _count) |
| } |
| |
| var endIndex: MinimalIndex { |
| return MinimalIndex( |
| collectionState: _collectionState, |
| position: _count, startIndex: 0, endIndex: _count) |
| } |
| |
| func index(after i: MinimalIndex) -> MinimalIndex { |
| return MinimalIndex( |
| collectionState: _collectionState, |
| position: i.position + 1, startIndex: 0, endIndex: _count) |
| } |
| |
| subscript(i: MinimalIndex) -> OpaqueValue<Int> { |
| expectUnreachable() |
| return OpaqueValue(0xffff) |
| } |
| |
| var _count: Int |
| var _collectionState: _CollectionState |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // filter() |
| //===----------------------------------------------------------------------===// |
| |
| var MinimalCollectionWithCustomFilter_timesFilterWasCalled: Int = 0 |
| |
| % for Implementation in [ 'Default', 'Custom' ]: |
| |
| struct MinimalCollectionWith${Implementation}Filter<Element> |
| : Collection { |
| |
| init(_ data: [Element], underestimatedCount: UnderestimatedCountBehavior) { |
| self._data = MinimalCollection( |
| elements: data, underestimatedCount: underestimatedCount) |
| } |
| |
| func makeIterator() -> MinimalIterator<Element> { |
| return _data.makeIterator() |
| } |
| |
| var startIndex: MinimalIndex { |
| return _data.startIndex |
| } |
| |
| var endIndex: MinimalIndex { |
| return _data.endIndex |
| } |
| |
| func index(after i: MinimalIndex) -> MinimalIndex { |
| return _data.index(after: i) |
| } |
| |
| subscript(i: MinimalIndex) -> Element { |
| return _data[i] |
| } |
| |
| var _data: MinimalCollection<Element> |
| |
| |
| % if Implementation == 'Custom': |
| |
| static var timesFilterWasCalled: Int { |
| get { |
| return MinimalCollectionWithCustomFilter_timesFilterWasCalled |
| } |
| set { |
| MinimalCollectionWithCustomFilter_timesFilterWasCalled = newValue |
| } |
| } |
| |
| func filter( |
| _ isIncluded: (Element) throws -> Bool |
| ) rethrows -> [Element] { |
| MinimalCollectionWithCustomFilter.timesFilterWasCalled += 1 |
| return try _data.filter(isIncluded) |
| } |
| |
| % end |
| |
| } |
| |
| % end |
| |
| func callStaticCollectionFilter( |
| _ sequence: MinimalCollectionWithDefaultFilter<OpaqueValue<Int>>, |
| _ isIncluded: (OpaqueValue<Int>) -> Bool |
| ) -> [OpaqueValue<Int>] { |
| var result = sequence.filter(isIncluded) |
| expectType([OpaqueValue<Int>].self, &result) |
| return result |
| } |
| |
| func callStaticCollectionFilter( |
| _ sequence: MinimalCollectionWithCustomFilter<OpaqueValue<Int>>, |
| _ isIncluded: (OpaqueValue<Int>) -> Bool |
| ) -> [OpaqueValue<Int>] { |
| var result = sequence.filter(isIncluded) |
| expectType([OpaqueValue<Int>].self, &result) |
| return result |
| } |
| |
| func callGenericCollectionFilter<S : Collection>( |
| _ sequence: S, |
| _ isIncluded: (S.Iterator.Element) -> Bool |
| ) -> [S.Iterator.Element] { |
| var result = sequence.filter(isIncluded) |
| expectType(Array<S.Iterator.Element>.self, &result) |
| return result |
| } |
| |
| % for Implementation in [ 'Default', 'Custom' ]: |
| |
| % for dispatch in [ 'Static', 'Generic' ]: |
| |
| CollectionTypeTests.test("filter/Collection/${Implementation}Implementation/${dispatch}") { |
| for test in filterTests { |
| for underestimatedCountBehavior in [ |
| UnderestimatedCountBehavior.precise, |
| UnderestimatedCountBehavior.half, |
| UnderestimatedCountBehavior.value(0) |
| ] { |
| let s = MinimalCollectionWith${Implementation}Filter<OpaqueValue<Int>>( |
| test.sequence.map(OpaqueValue.init), |
| underestimatedCount: underestimatedCountBehavior) |
| let closureLifetimeTracker = LifetimeTracked(0) |
| expectEqual(1, LifetimeTracked.instances) |
| var timesClosureWasCalled = 0 |
| % if Implementation == 'Custom': |
| MinimalCollectionWithCustomFilter<OpaqueValue<Int>>.timesFilterWasCalled = 0 |
| % end |
| var result = call${dispatch}CollectionFilter(s) { |
| (element) in |
| _blackHole(closureLifetimeTracker) |
| timesClosureWasCalled += 1 |
| return test.includeElement(element.value) |
| } |
| expectType([OpaqueValue<Int>].self, &result) |
| expectEqual(test.expected, result.map { $0.value }) |
| % if Implementation == 'Custom': |
| expectEqual(1, MinimalCollectionWithCustomFilter<OpaqueValue<Int>>.timesFilterWasCalled) |
| % end |
| expectEqual( |
| test.sequence, s.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, |
| "filter() should not reserve capacity" |
| + "(it does not know how much the predicate will filter out)") |
| } |
| } |
| } |
| |
| % end |
| |
| % end |
| |
| //===----------------------------------------------------------------------===// |
| // map() |
| //===----------------------------------------------------------------------===// |
| var MinimalCollectionWithCustomMap_timesMapWasCalled: Int = 0 |
| |
| % for Implementation in [ 'Default', 'Custom' ]: |
| |
| struct MinimalCollectionWith${Implementation}Map<Element> |
| : Collection { |
| |
| init(_ data: [Element], underestimatedCount: UnderestimatedCountBehavior) { |
| self._data = MinimalCollection( |
| elements: data, underestimatedCount: underestimatedCount) |
| } |
| |
| func makeIterator() -> MinimalIterator<Element> { |
| return _data.makeIterator() |
| } |
| |
| var startIndex: MinimalIndex { |
| return _data.startIndex |
| } |
| |
| var endIndex: MinimalIndex { |
| return _data.endIndex |
| } |
| |
| func index(after i: MinimalIndex) -> MinimalIndex { |
| return _data.index(after: i) |
| } |
| |
| subscript(i: MinimalIndex) -> Element { |
| return _data[i] |
| } |
| |
| var _data: MinimalCollection<Element> |
| |
| |
| % if Implementation == 'Custom': |
| |
| static var timesMapWasCalled: Int { |
| get { |
| return MinimalCollectionWithCustomMap_timesMapWasCalled |
| } |
| set { |
| MinimalCollectionWithCustomMap_timesMapWasCalled = newValue |
| } |
| } |
| |
| func map<T>( |
| _ transform: (Element) throws -> T |
| ) rethrows -> [T] { |
| MinimalCollectionWithCustomMap.timesMapWasCalled += 1 |
| return try _data.map(transform) |
| } |
| |
| % end |
| |
| } |
| |
| % end |
| |
| func callStaticCollectionMap<T>( |
| _ collection: MinimalCollectionWithDefaultMap<OpaqueValue<Int>>, |
| transform: (OpaqueValue<Int>) -> T |
| ) -> [T] { |
| var result = collection.map(transform) |
| expectType([T].self, &result) |
| return result |
| } |
| |
| func callStaticCollectionMap<T>( |
| _ collection: MinimalCollectionWithCustomMap<OpaqueValue<Int>>, |
| transform: (OpaqueValue<Int>) -> T |
| ) -> [T] { |
| var result = collection.map(transform) |
| expectType([T].self, &result) |
| return result |
| } |
| |
| func callGenericCollectionMap<C : Collection, T>( |
| _ collection: C, |
| transform: (C.Iterator.Element) -> T |
| ) -> [T] { |
| var result = collection.map(transform) |
| expectType([T].self, &result) |
| return result |
| } |
| |
| % for Implementation in [ 'Default', 'Custom' ]: |
| |
| % for dispatch in [ 'Static', 'Generic' ]: |
| |
| CollectionTypeTests.test( |
| "map/Collection/${Implementation}Implementation/${dispatch}" |
| ) { |
| for test in mapTests { |
| for underestimatedCountBehavior in [ |
| UnderestimatedCountBehavior.precise, |
| UnderestimatedCountBehavior.half, |
| UnderestimatedCountBehavior.value(0) |
| ] { |
| let s = MinimalCollectionWith${Implementation}Map< |
| OpaqueValue<Int> |
| >( |
| test.sequence.map(OpaqueValue.init), |
| underestimatedCount: underestimatedCountBehavior) |
| let closureLifetimeTracker = LifetimeTracked(0) |
| expectEqual(1, LifetimeTracked.instances) |
| var timesClosureWasCalled = 0 |
| % if Implementation == 'Custom': |
| MinimalCollectionWithCustomMap< |
| OpaqueValue<Int> |
| >.timesMapWasCalled = 0 |
| % end |
| var result = call${dispatch}CollectionMap(s) { |
| (element: OpaqueValue<Int>) -> OpaqueValue<Int32> in |
| _blackHole(closureLifetimeTracker) |
| timesClosureWasCalled += 1 |
| return OpaqueValue(Int32(test.transform(element.value))) |
| } |
| expectType([OpaqueValue<Int32>].self, &result) |
| expectEqual(test.expected, result.map { $0.value }) |
| % if Implementation == 'Custom': |
| expectEqual( |
| 1, MinimalCollectionWithCustomMap< |
| OpaqueValue<Int> |
| >.timesMapWasCalled) |
| % end |
| expectEqual(test.sequence, s.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") |
| } |
| } |
| } |
| |
| % end |
| |
| % end |
| |
| //===----------------------------------------------------------------------===// |
| // flatMap() |
| //===----------------------------------------------------------------------===// |
| |
| % TLazyFlatMapTest = gyb.parse_template(os.path.join(os.path.dirname(__file__), "Inputs/flatMap.gyb")) |
| % LazyFlatMapTest = gyb.execute_template(TLazyFlatMapTest, Test='CollectionTypeTests', Kinds=['Collection', 'BidirectionalCollection']) |
| ${LazyFlatMapTest} |
| |
| //===----------------------------------------------------------------------===// |
| // underestimatedCount |
| //===----------------------------------------------------------------------===// |
| |
| CollectionTypeTests.test("underestimatedCount/Collection/DefaultImplementation") { |
| do { |
| let s = CollectionWithDefaultUnderestimatedCount(count: 0) |
| expectEqual(0, callGenericUnderestimatedCount(s)) |
| } |
| do { |
| let s = CollectionWithDefaultUnderestimatedCount(count: 5) |
| expectEqual(5, callGenericUnderestimatedCount(s)) |
| } |
| } |
| |
| struct CollectionWithCustomUnderestimatedCount : Collection { |
| init(underestimatedCount: Int) { |
| self._underestimatedCount = underestimatedCount |
| self._collectionState = |
| _CollectionState(newRootStateForElementCount: 0xffff) |
| } |
| |
| func makeIterator() -> MinimalIterator<OpaqueValue<Int>> { |
| expectUnreachable() |
| return MinimalIterator([]) |
| } |
| |
| var startIndex: MinimalIndex { |
| expectUnreachable() |
| return MinimalIndex( |
| collectionState: _collectionState, |
| position: 0, startIndex: 0, endIndex: 0xffff) |
| } |
| |
| var endIndex: MinimalIndex { |
| expectUnreachable() |
| return MinimalIndex( |
| collectionState: _collectionState, |
| position: 0xffff, startIndex: 0, endIndex: 0xffff) |
| } |
| |
| func index(after i: MinimalIndex) -> MinimalIndex { |
| return MinimalIndex( |
| collectionState: _collectionState, |
| position: i.position + 1, startIndex: 0, endIndex: 0xffff) |
| } |
| |
| subscript(i: MinimalIndex) -> OpaqueValue<Int> { |
| expectUnreachable() |
| return OpaqueValue(0xffff) |
| } |
| |
| var underestimatedCount: Int { |
| return _underestimatedCount |
| } |
| |
| let _underestimatedCount: Int |
| var _collectionState: _CollectionState |
| } |
| |
| CollectionTypeTests.test("underestimatedCount/Collection/CustomImplementation") { |
| do { |
| let s = CollectionWithCustomUnderestimatedCount(underestimatedCount: 0) |
| expectEqual(0, callGenericUnderestimatedCount(s)) |
| } |
| do { |
| let s = CollectionWithCustomUnderestimatedCount(underestimatedCount: 5) |
| expectEqual(5, callGenericUnderestimatedCount(s)) |
| } |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Collection.makeIterator(), Collection.Iterator |
| //===----------------------------------------------------------------------===// |
| |
| struct MinimalCollectionWithDefaultIterator : Collection { |
| init(count: Int) { |
| self._count = count |
| self._collectionState = |
| _CollectionState(newRootStateForElementCount: count) |
| } |
| |
| var startIndex: MinimalIndex { |
| return MinimalIndex( |
| collectionState: _collectionState, |
| position: 0, startIndex: 0, endIndex: _count) |
| } |
| |
| var endIndex: MinimalIndex { |
| return MinimalIndex( |
| collectionState: _collectionState, |
| position: _count, startIndex: 0, endIndex: _count) |
| } |
| |
| func index(after i: MinimalIndex) -> MinimalIndex { |
| return MinimalIndex( |
| collectionState: _collectionState, |
| position: i.position + 1, startIndex: 0, endIndex: _count) |
| } |
| |
| subscript(i: MinimalIndex) -> OpaqueValue<Int> { |
| return OpaqueValue(i.position + 1) |
| } |
| |
| var _count: Int |
| var _collectionState: _CollectionState |
| } |
| |
| func callGenericIterator<S : Sequence>(_ sequence: S) -> S.Iterator { |
| return sequence.makeIterator() |
| } |
| |
| CollectionTypeTests.test("Collection.makeIterator()/DefaultImplementation") { |
| for count in [ 0, 5 ] { |
| let collection = MinimalCollectionWithDefaultIterator(count: count) |
| |
| do { |
| // Check the return type of the function when called statically. |
| var iter = collection.makeIterator() |
| expectType( |
| IndexingIterator<MinimalCollectionWithDefaultIterator>.self, |
| &iter) |
| } |
| |
| do { |
| // Check the return type of the function when called generically. |
| var iter = callGenericIterator(collection) |
| expectType( |
| IndexingIterator<MinimalCollectionWithDefaultIterator>.self, |
| &iter) |
| } |
| |
| checkCollection( |
| Array(1..<count+1).map(OpaqueValue.init) as [OpaqueValue<Int>], |
| collection |
| ) { $0.value == $1.value } |
| } |
| } |
| |
| struct MinimalCollectionWithCustomIterator : Collection { |
| init(count: Int) { |
| self._count = count |
| self._collectionState = |
| _CollectionState(newRootStateForElementCount: count) |
| } |
| |
| static var timesIteratorWasCalled: Int = 0 |
| |
| func makeIterator() -> MinimalIterator<OpaqueValue<Int>> { |
| MinimalCollectionWithCustomIterator.timesIteratorWasCalled += 1 |
| return MinimalIterator<OpaqueValue<Int>>( |
| Array(1..<_count+1).map(OpaqueValue.init) as [OpaqueValue<Int>] |
| ) |
| } |
| |
| var startIndex: MinimalIndex { |
| return MinimalIndex( |
| collectionState: _collectionState, |
| position: 0, startIndex: 0, endIndex: _count) |
| } |
| |
| var endIndex: MinimalIndex { |
| return MinimalIndex( |
| collectionState: _collectionState, |
| position: _count, startIndex: 0, endIndex: _count) |
| } |
| |
| func index(after i: MinimalIndex) -> MinimalIndex { |
| return MinimalIndex( |
| collectionState: _collectionState, |
| position: i.position + 1, startIndex: 0, endIndex: _count) |
| } |
| |
| subscript(i: MinimalIndex) -> OpaqueValue<Int> { |
| return OpaqueValue(i.position + 1) |
| } |
| |
| var _count: Int |
| var _collectionState: _CollectionState |
| } |
| |
| CollectionTypeTests.test("Collection.makeIterator()/CustomImplementation") { |
| for count in [ 0, 5 ] { |
| let collection = MinimalCollectionWithCustomIterator(count: count) |
| |
| do { |
| // Check the return type of the function when called statically. |
| MinimalCollectionWithCustomIterator.timesIteratorWasCalled = 0 |
| var iter = collection.makeIterator() |
| expectType( |
| MinimalIterator<OpaqueValue<Int>>.self, |
| &iter) |
| expectEqual(1, MinimalCollectionWithCustomIterator.timesIteratorWasCalled) |
| } |
| |
| do { |
| MinimalCollectionWithCustomIterator.timesIteratorWasCalled = 0 |
| // Check the return type of the function when called generically. |
| var iter = callGenericIterator(collection) |
| expectType( |
| MinimalIterator<OpaqueValue<Int>>.self, |
| &iter) |
| expectEqual(1, MinimalCollectionWithCustomIterator.timesIteratorWasCalled) |
| } |
| |
| checkCollection( |
| Array(1..<count+1).map(OpaqueValue.init) as [OpaqueValue<Int>], |
| collection, |
| resiliencyChecks: .none) { $0.value == $1.value } |
| } |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // subscript(_: Range<Index>), Collection.SubSequence |
| //===----------------------------------------------------------------------===// |
| |
| CollectionTypeTests.test("subscript(_: Range<Index>)/Dispatch") { |
| let tester = CollectionLog.dispatchTester([OpaqueValue(1)]) |
| _ = tester[tester.startIndex..<tester.endIndex] |
| let log = tester.log |
| let log2 = tester.log.subscriptRange |
| expectCustomizable(tester, tester.log.subscriptRange) |
| } |
| |
| CollectionTypeTests.test("subscript(_: Range<Index>)/writeback") { |
| // This code used to crash in materializeForSet. The issue only reproduced |
| // in non-generic code. rdar://22109071 |
| var collection = MinimalMutableRandomAccessCollection( |
| elements: [ 5, 4, 3, 2, 1, 0, -1, -2, -3, -4 ]) |
| var i = collection.startIndex |
| var j = collection.index(i, offsetBy: 5) |
| collection[i..<j].sort() |
| expectEqualSequence( |
| [ 1, 2, 3, 4, 5, 0, -1, -2, -3, -4 ], collection) |
| } |
| |
| CollectionTypeTests.test("subscript(_: Range<Index>)/defaultImplementation/sliceTooLarge") |
| .crashOutputMatches("Cannot replace a slice of a MutableCollection with a slice of a larger size") |
| .code { |
| var x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] |
| expectCrashLater() |
| x.withUnsafeMutableBufferPointer { buffer in |
| buffer[2..<4] = buffer[4..<8] |
| } |
| } |
| |
| CollectionTypeTests.test("subscript(_: Range<Index>)/defaultImplementation/sliceTooSmall") |
| .crashOutputMatches("Cannot replace a slice of a MutableCollection with a slice of a smaller size") |
| .code { |
| var x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] |
| expectCrashLater() |
| x.withUnsafeMutableBufferPointer { buffer in |
| buffer[2..<6] = buffer[6..<8] |
| } |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // isEmpty |
| //===----------------------------------------------------------------------===// |
| |
| CollectionTypeTests.test("isEmpty/dispatch") { |
| let tester = CollectionLog.dispatchTester([OpaqueValue(1)]) |
| _ = tester.isEmpty |
| expectCustomizable(tester, tester.log.isEmpty) |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // first |
| //===----------------------------------------------------------------------===// |
| |
| CollectionTypeTests.test("first/dispatch") { |
| let tester = CollectionLog.dispatchTester([OpaqueValue(1)]) |
| _ = tester.first |
| expectCustomizable(tester, tester.log.first) |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // count |
| //===----------------------------------------------------------------------===// |
| |
| CollectionTypeTests.test("count/dispatch") { |
| let tester = CollectionLog.dispatchTester([OpaqueValue(1)]) |
| _ = tester.count |
| expectCustomizable(tester, tester.log.count) |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // index(of:) |
| //===----------------------------------------------------------------------===// |
| |
| CollectionTypeTests.test("index(of:)/WhereElementIsEquatable/dispatch") { |
| let tester = CollectionLog.dispatchTester([MinimalEquatableValue(1)]) |
| _ = tester.index(of: MinimalEquatableValue(1)) |
| expectCustomizable(tester, tester.log._customIndexOfEquatableElement) |
| } |
| |
| // FIXME: underscores are a workaround for: |
| // <rdar://problem/20582358> Commenting out one line determines whether a |
| // completely different line type-checks |
| func callGenericFind_< |
| C : Collection |
| >(_ collection: C, _ element: C.Iterator.Element) -> C.Index? |
| where C.Iterator.Element : Equatable { |
| return collection.index(of: element) |
| } |
| |
| func callStaticFind_( |
| _ set: Set<MinimalHashableValue>, |
| _ element: MinimalHashableValue |
| ) -> Set<MinimalHashableValue>.Index? { |
| return set.index(of: element) |
| } |
| |
| % for dispatch in [ 'Static', 'Generic' ]: |
| |
| // FIXME: implement the same optimization for Dictionary. |
| // FIXME: move to the file where other Set tests live. |
| CollectionTypeTests.test("Set<T>.find/CustomImplementation/${dispatch}") { |
| for test in findTests { |
| let s = Set<MinimalHashableValue>( |
| test.sequence.map { MinimalHashableValue($0.value) }) |
| MinimalHashableValue.timesEqualEqualWasCalled = 0 |
| MinimalHashableValue.timesHashValueWasCalled = 0 |
| expectEqual( |
| test.expected |
| .map { _ in MinimalHashableValue(test.element.value) }, |
| call${dispatch}Find_(s, MinimalHashableValue(test.element.value)) |
| .map { s[$0] }, |
| stackTrace: SourceLocStack().with(test.loc)) |
| if test.sequence.isEmpty { |
| expectEqual( |
| 0, MinimalHashableValue.timesEqualEqualWasCalled, |
| stackTrace: SourceLocStack().with(test.loc)) |
| expectEqual( |
| 0, MinimalHashableValue.timesHashValueWasCalled, |
| stackTrace: SourceLocStack().with(test.loc)) |
| } else { |
| expectNotEqual( |
| 0, MinimalHashableValue.timesHashValueWasCalled, |
| stackTrace: SourceLocStack().with(test.loc)) |
| } |
| if test.expected != nil { |
| expectNotEqual( |
| 0, MinimalHashableValue.timesEqualEqualWasCalled, |
| stackTrace: SourceLocStack().with(test.loc)) |
| } |
| } |
| } |
| |
| % end |
| |
| extension Collection where |
| Iterator.Element : Equatable, |
| |
| // FIXME: the following constraints should go away after |
| // <rdar://problem/20715697> Collection.SubSlice should constrain its |
| // Element type |
| SubSequence : Collection, |
| SubSequence.SubSequence == SubSequence, |
| SubSequence.Iterator.Element == Iterator.Element, |
| SubSequence.Index == Index { |
| |
| func _test_indicesOf(_ element: Iterator.Element) -> [Index] { |
| var result: [Index] = [] |
| var tail = self[startIndex..<endIndex] |
| while let foundIndex = tail.index(of: element) { |
| result.append(foundIndex) |
| tail = tail[index(after: foundIndex)..<endIndex] |
| } |
| return result |
| } |
| } |
| |
| CollectionTypeTests.test("index(of:)/ContinueSearch") { |
| do { |
| let c = MinimalCollection(elements: [] as [MinimalEquatableValue]) |
| expectEqualSequence( |
| [], |
| c._test_indicesOf(MinimalEquatableValue(1))) |
| } |
| |
| do { |
| let c = MinimalCollection( |
| elements: [1, 2, 1, 3, 1].map(MinimalEquatableValue.init)) |
| let foundIndices = c._test_indicesOf(MinimalEquatableValue(1)) |
| let actual = foundIndices.map { c.distance(from: c.startIndex, to: $0) } |
| expectEqualSequence( |
| [ 0, 2, 4 ], |
| actual |
| ) |
| } |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Collection indices types |
| //===----------------------------------------------------------------------===// |
| |
| // SR-2121 |
| extension Collection { |
| func testIndicesElementType() { |
| for index in self.indices { |
| _ = self[index] |
| } |
| } |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Collection.split() |
| //===----------------------------------------------------------------------===// |
| |
| CollectionTypeTests.test("Collection/split/dispatch") { |
| var tester = CollectionLog.dispatchTester([OpaqueValue(1)]) |
| _ = tester.split { $0.value == 1 } |
| expectCustomizable(tester, tester.log.split) |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // prefix(through:) |
| //===----------------------------------------------------------------------===// |
| |
| CollectionTypeTests.test("Collection/prefix(through:)/dispatch") { |
| var tester = CollectionLog.dispatchTester([1, 2, 3].map(OpaqueValue.init)) |
| _ = tester.prefix(through: 1) |
| expectCustomizable(tester, tester.log.prefixThrough) |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // prefix(upTo:) |
| //===----------------------------------------------------------------------===// |
| |
| CollectionTypeTests.test("Collection/prefix(upTo:)/dispatch") { |
| var tester = CollectionLog.dispatchTester([OpaqueValue(1)]) |
| _ = tester.prefix(upTo: 1) |
| expectCustomizable(tester, tester.log.prefixUpTo) |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // suffix(from:) |
| //===----------------------------------------------------------------------===// |
| |
| CollectionTypeTests.test("Collection/suffix(from:)/dispatch") { |
| var tester = CollectionLog.dispatchTester([1, 2, 3].map(OpaqueValue.init)) |
| _ = tester.suffix(from: 1) |
| expectCustomizable(tester, tester.log.suffixFrom) |
| } |
| |
| |
| //===----------------------------------------------------------------------===// |
| // MutableCollection |
| //===----------------------------------------------------------------------===// |
| |
| //===----------------------------------------------------------------------===// |
| // partition(by:) |
| //===----------------------------------------------------------------------===// |
| |
| CollectionTypeTests.test("partition(by:)/dispatch") { |
| var tester = MutableCollectionLog.dispatchTester([OpaqueValue(1)]) |
| _ = tester.partition(by: { _ in true }) |
| expectCustomizable(tester, tester.log.partitionBy) |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // _withUnsafeMutableBufferPointerIfSupported() |
| //===----------------------------------------------------------------------===// |
| |
| CollectionTypeTests.test("_withUnsafeMutableBufferPointerIfSupported/dispatch") { |
| var tester = MutableCollectionLog.dispatchTester([OpaqueValue(1)]) |
| _ = tester._withUnsafeMutableBufferPointerIfSupported { _ in () } |
| expectCustomizable(tester, tester.log._withUnsafeMutableBufferPointerIfSupported) |
| } |
| |
| |
| //===----------------------------------------------------------------------===// |
| // Associated Type Inference |
| //===----------------------------------------------------------------------===// |
| |
| // This section verifies that only the absolutely minimal protocol requirements |
| // are required to declare each kind of collection. All remaining requirements |
| // and associated types should be either inferred from the declared properties |
| // and methods or inherited as defaults via protocol extension. |
| |
| struct FatalIndex : Comparable { } |
| func <(lhs: FatalIndex, rhs: FatalIndex) -> Bool { fatalError() } |
| func ==(lhs: FatalIndex, rhs: FatalIndex) -> Bool { fatalError() } |
| |
| % for Traversal in TRAVERSALS: |
| % Collection = collectionForTraversal(Traversal) |
| % Self = 'Fatal' + Collection |
| % Slice = sliceTypeName(Traversal, False, False) |
| % Indices = defaultIndicesForTraversal(Traversal) |
| |
| struct ${Self}<T> : ${Collection} { |
| var startIndex: FatalIndex { fatalError() } |
| var endIndex: FatalIndex { fatalError() } |
| subscript(i: FatalIndex) -> T { fatalError() } |
| func index(after i: FatalIndex) -> FatalIndex { fatalError() } |
| % if Traversal in ['Bidirectional', 'RandomAccess']: |
| func index(before i: FatalIndex) -> FatalIndex { fatalError() } |
| % end |
| } |
| |
| CollectionTypeTests.test("AssociatedTypes/${Collection}") { |
| typealias C = ${Self}<Void> |
| expectCollectionAssociatedTypes( |
| collectionType: C.self, |
| iteratorType: IndexingIterator<C>.self, |
| subSequenceType: ${Slice}<C>.self, |
| indexType: FatalIndex.self, |
| indexDistanceType: Int.self, |
| indicesType: ${Indices}<C>.self) |
| } |
| % end |
| |
| |
| runAllTests() |